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

« back to all changes in this revision

Viewing changes to src/calibre/gui2/library.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:
9
9
from PyQt4.QtGui import QTableView, QAbstractItemView, QColor, \
10
10
                        QItemDelegate, QPainterPath, QLinearGradient, QBrush, \
11
11
                        QPen, QStyle, QPainter, QLineEdit, \
12
 
                        QPalette, QImage, QApplication, QMenu, QStyledItemDelegate
 
12
                        QPalette, QImage, QApplication, QMenu, \
 
13
                        QStyledItemDelegate, QCompleter
13
14
from PyQt4.QtCore import QAbstractTableModel, QVariant, Qt, QString, \
14
15
                         SIGNAL, QObject, QSize, QModelIndex, QDate
15
16
 
16
17
from calibre import strftime
17
18
from calibre.ptempfile import PersistentTemporaryFile
 
19
from calibre.utils.pyparsing import ParseException
18
20
from calibre.library.database2 import FIELD_MAP
19
21
from calibre.gui2 import NONE, TableView, qstring_to_unicode, config, \
20
22
                         error_dialog
 
23
from calibre.gui2.widgets import EnLineEdit, TagsLineEdit
21
24
from calibre.utils.search_query_parser import SearchQueryParser
22
25
from calibre.ebooks.metadata.meta import set_metadata as _set_metadata
23
 
from calibre.ebooks.metadata import string_to_authors
 
26
from calibre.ebooks.metadata import string_to_authors, fmt_sidx
24
27
 
25
28
class LibraryDelegate(QItemDelegate):
26
29
    COLOR    = QColor("blue")
98
101
        qde.setCalendarPopup(True)
99
102
        return qde
100
103
 
 
104
class PubDateDelegate(QStyledItemDelegate):
 
105
 
 
106
    def displayText(self, val, locale):
 
107
        return val.toDate().toString('MMM yyyy')
 
108
 
 
109
    def createEditor(self, parent, option, index):
 
110
        qde = QStyledItemDelegate.createEditor(self, parent, option, index)
 
111
        qde.setDisplayFormat('MM yyyy')
 
112
        qde.setMinimumDate(QDate(101,1,1))
 
113
        qde.setCalendarPopup(True)
 
114
        return qde
 
115
 
 
116
class TextDelegate(QStyledItemDelegate):
 
117
 
 
118
    def __init__(self, parent):
 
119
        '''
 
120
        Delegate for text data. If auto_complete_function needs to return a list
 
121
        of text items to auto-complete with. The funciton is None no
 
122
        auto-complete will be used.
 
123
        '''
 
124
        QStyledItemDelegate.__init__(self, parent)
 
125
        self.auto_complete_function = None
 
126
 
 
127
    def set_auto_complete_function(self, f):
 
128
        self.auto_complete_function = f
 
129
 
 
130
    def createEditor(self, parent, option, index):
 
131
        editor = EnLineEdit(parent)
 
132
        if self.auto_complete_function:
 
133
            complete_items = [i[1] for i in self.auto_complete_function()]
 
134
            completer = QCompleter(complete_items, self)
 
135
            completer.setCaseSensitivity(Qt.CaseInsensitive)
 
136
            completer.setCompletionMode(QCompleter.InlineCompletion)
 
137
            editor.setCompleter(completer)
 
138
        return editor
 
139
 
 
140
class TagsDelegate(QStyledItemDelegate):
 
141
 
 
142
    def __init__(self, parent):
 
143
        QStyledItemDelegate.__init__(self, parent)
 
144
        self.db = None
 
145
 
 
146
    def set_database(self, db):
 
147
        self.db = db
 
148
 
 
149
    def createEditor(self, parent, option, index):
 
150
        if self.db:
 
151
            editor = TagsLineEdit(parent, self.db.all_tags())
 
152
        else:
 
153
            editor = EnLineEdit(parent)
 
154
        return editor
 
155
 
101
156
class BooksModel(QAbstractTableModel):
102
 
    coding = zip(
103
 
    [1000,900,500,400,100,90,50,40,10,9,5,4,1],
104
 
    ["M","CM","D","CD","C","XC","L","XL","X","IX","V","IV","I"]
105
 
    )
106
 
 
107
157
    headers = {
108
158
                        'title'     : _("Title"),
109
159
                        'authors'   : _("Author(s)"),
110
160
                        'size'      : _("Size (MB)"),
111
161
                        'timestamp' : _("Date"),
 
162
                        'pubdate'   : _('Published'),
112
163
                        'rating'    : _('Rating'),
113
164
                        'publisher' : _("Publisher"),
114
165
                        'tags'      : _("Tags"),
115
166
                        'series'    : _("Series"),
116
167
                        }
117
168
 
118
 
    @classmethod
119
 
    def roman(cls, num):
120
 
        if num <= 0 or num >= 4000 or int(num) != num:
121
 
            return str(num)
122
 
        result = []
123
 
        for d, r in cls.coding:
124
 
            while num >= d:
125
 
                result.append(r)
126
 
                num -= d
127
 
        return ''.join(result)
128
 
 
129
169
    def __init__(self, parent=None, buffer=40):
130
170
        QAbstractTableModel.__init__(self, parent)
131
171
        self.db = None
132
172
        self.column_map = config['column_map']
133
173
        self.editable_cols = ['title', 'authors', 'rating', 'publisher',
134
 
                              'tags', 'series', 'timestamp']
 
174
                              'tags', 'series', 'timestamp', 'pubdate']
135
175
        self.default_image = QImage(':/images/book.svg')
136
176
        self.sorted_on = ('timestamp', Qt.AscendingOrder)
137
177
        self.last_search = '' # The last search performed on this model
149
189
        if cols != self.column_map:
150
190
            self.column_map = cols
151
191
            self.reset()
152
 
            try:
153
 
                idx = self.column_map.index('rating')
154
 
            except ValueError:
155
 
                idx = -1
156
 
            try:
157
 
                tidx = self.column_map.index('timestamp')
158
 
            except ValueError:
159
 
                tidx = -1
160
 
 
161
 
            self.emit(SIGNAL('columns_sorted(int,int)'), idx, tidx)
162
 
 
 
192
            self.emit(SIGNAL('columns_sorted()'))
163
193
 
164
194
    def set_database(self, db):
165
195
        self.db = db
186
216
        self.db = None
187
217
        self.reset()
188
218
 
189
 
    def add_books(self, paths, formats, metadata, uris=[], add_duplicates=False):
190
 
        ret = self.db.add_books(paths, formats, metadata, uris,
 
219
    def add_books(self, paths, formats, metadata, add_duplicates=False):
 
220
        ret = self.db.add_books(paths, formats, metadata,
191
221
                                 add_duplicates=add_duplicates)
192
222
        self.count_changed()
193
223
        return ret
204
234
        ''' Return list indices of all cells in index.row()'''
205
235
        return [ self.index(index.row(), c) for c in range(self.columnCount(None))]
206
236
 
207
 
    def save_to_disk(self, rows, path, single_dir=False, single_format=None,
208
 
                     callback=None):
209
 
        rows = [row.row() for row in rows]
210
 
        if single_format is None:
211
 
            return self.db.export_to_dir(path, rows,
212
 
                                         self.sorted_on[0] == 'authors',
213
 
                                         single_dir=single_dir,
214
 
                                         callback=callback)
215
 
        else:
216
 
            return self.db.export_single_format_to_dir(path, rows,
217
 
                                                       single_format,
218
 
                                                       callback=callback)
219
 
 
 
237
    @property
 
238
    def by_author(self):
 
239
        return self.sorted_on[0] == 'authors'
220
240
 
221
241
    def delete_books(self, indices):
222
242
        ids = map(self.id, indices)
248
268
            self.count_changed()
249
269
 
250
270
    def search(self, text, refinement, reset=True):
251
 
        self.db.search(text)
 
271
        try:
 
272
            self.db.search(text)
 
273
        except ParseException:
 
274
            self.emit(SIGNAL('searched(PyQt_PyObject)'), False)
 
275
            return
252
276
        self.last_search = text
253
277
        if reset:
254
278
            self.clear_caches()
255
279
            self.reset()
 
280
        if self.last_search:
 
281
            self.emit(SIGNAL('searched(PyQt_PyObject)'), True)
 
282
 
256
283
 
257
284
    def sort(self, col, order, reset=True):
258
285
        if not self.db:
323
350
        series = self.db.series(idx)
324
351
        if series:
325
352
            sidx = self.db.series_index(idx)
326
 
            sidx = self.__class__.roman(sidx) if self.use_roman_numbers else str(sidx)
 
353
            sidx = fmt_sidx(sidx, use_roman = self.use_roman_numbers)
327
354
            data[_('Series')] = _('Book <font face="serif">%s</font> of %s.')%(sidx, series)
328
355
 
329
356
        return data
397
424
        else:
398
425
            return metadata
399
426
 
400
 
    def get_preferred_formats_from_ids(self, ids, all_formats, mode='r+b'):
 
427
    def get_preferred_formats_from_ids(self, ids, formats, paths=False,
 
428
                              set_metadata=False, specific_format=None,
 
429
                              exclude_auto=False, mode='r+b'):
401
430
        ans = []
 
431
        need_auto = []
 
432
        if specific_format is not None:
 
433
            formats = [specific_format.lower()]
402
434
        for id in ids:
403
435
            format = None
404
436
            fmts = self.db.formats(id, index_is_id=True)
405
437
            if not fmts:
406
438
                fmts = ''
407
 
            available_formats = set(fmts.lower().split(','))
408
 
            for f in all_formats:
409
 
                if f.lower() in available_formats:
410
 
                    format = f.lower()
 
439
            db_formats = set(fmts.lower().split(','))
 
440
            available_formats = set([f.lower() for f in formats])
 
441
            u = available_formats.intersection(db_formats)
 
442
            for f in formats:
 
443
                if f.lower() in u:
 
444
                    format = f
411
445
                    break
412
 
            if format is None:
413
 
                ans.append(format)
 
446
            if format is not None:
 
447
                pt = PersistentTemporaryFile(suffix='.'+format)
 
448
                pt.write(self.db.format(id, format, index_is_id=True))
 
449
                pt.flush()
 
450
                if set_metadata:
 
451
                    _set_metadata(pt, self.db.get_metadata(id, get_cover=True, index_is_id=True),
 
452
                                  format)
 
453
                pt.close() if paths else pt.seek(0)
 
454
                ans.append(pt)
414
455
            else:
415
 
                f = self.db.format(id, format, index_is_id=True, as_file=True,
416
 
                                   mode=mode)
417
 
                ans.append(f)
418
 
        return ans
419
 
 
420
 
 
 
456
                need_auto.append(id)
 
457
                if not exclude_auto:
 
458
                    ans.append(None)
 
459
        return ans, need_auto
421
460
 
422
461
    def get_preferred_formats(self, rows, formats, paths=False,
423
 
                              set_metadata=False, specific_format=None):
 
462
                              set_metadata=False, specific_format=None,
 
463
                              exclude_auto=False):
424
464
        ans = []
 
465
        need_auto = []
425
466
        if specific_format is not None:
426
467
            formats = [specific_format.lower()]
427
468
        for row in (row.row() for row in rows):
446
487
                pt.close() if paths else pt.seek(0)
447
488
                ans.append(pt)
448
489
            else:
449
 
                ans.append(None)
450
 
        return ans
 
490
                need_auto.append(row)
 
491
                if not exclude_auto:
 
492
                    ans.append(None)
 
493
        return ans, need_auto
451
494
 
452
495
    def id(self, row):
453
496
        return self.db.id(getattr(row, 'row', lambda:row)())
486
529
        ridx = FIELD_MAP['rating']
487
530
        pidx = FIELD_MAP['publisher']
488
531
        tmdx = FIELD_MAP['timestamp']
 
532
        pddx = FIELD_MAP['pubdate']
489
533
        srdx = FIELD_MAP['series']
490
534
        tgdx = FIELD_MAP['tags']
491
535
        siix = FIELD_MAP['series_index']
502
546
                dt = dt - timedelta(seconds=time.timezone) + timedelta(hours=time.daylight)
503
547
                return QDate(dt.year, dt.month, dt.day)
504
548
 
 
549
        def pubdate(r):
 
550
            dt = self.db.data[r][pddx]
 
551
            if dt:
 
552
                dt = dt - timedelta(seconds=time.timezone) + timedelta(hours=time.daylight)
 
553
                return QDate(dt.year, dt.month, dt.day)
 
554
 
505
555
        def rating(r):
506
556
            r = self.db.data[r][ridx]
507
557
            r = r/2 if r else 0
520
570
        def series(r):
521
571
            series = self.db.data[r][srdx]
522
572
            if series:
523
 
                return series  + ' [%d]'%self.db.data[r][siix]
524
 
 
 
573
                idx = fmt_sidx(self.db.data[r][siix])
 
574
                return series + ' [%s]'%idx
525
575
        def size(r):
526
576
            size = self.db.data[r][sidx]
527
577
            if size:
532
582
                   'authors'  : authors,
533
583
                   'size'     : size,
534
584
                   'timestamp': timestamp,
 
585
                   'pubdate' : pubdate,
535
586
                   'rating'   : rating,
536
587
                   'publisher': publisher,
537
588
                   'tags'     : tags,
571
622
            if column not in self.editable_cols:
572
623
                return False
573
624
            val = int(value.toInt()[0]) if column == 'rating' else \
574
 
                  value.toDate() if column == 'timestamp' else \
 
625
                  value.toDate() if column in ('timestamp', 'pubdate') else \
575
626
                  unicode(value.toString())
576
627
            id = self.db.id(row)
577
628
            if column == 'rating':
579
630
                val *= 2
580
631
                self.db.set_rating(id, val)
581
632
            elif column == 'series':
582
 
                pat = re.compile(r'\[(\d+)\]')
 
633
                pat = re.compile(r'\[([.0-9]+)\]')
583
634
                match = pat.search(val)
584
635
                if match is not None:
585
 
                    self.db.set_series_index(id, int(match.group(1)))
 
636
                    self.db.set_series_index(id, float(match.group(1)))
586
637
                    val = pat.sub('', val)
587
638
                val = val.strip()
588
639
                if val:
592
643
                    return False
593
644
                dt = datetime(val.year(), val.month(), val.day()) + timedelta(seconds=time.timezone) - timedelta(hours=time.daylight)
594
645
                self.db.set_timestamp(id, dt)
 
646
            elif column == 'pubdate':
 
647
                if val.isNull() or not val.isValid():
 
648
                    return False
 
649
                dt = datetime(val.year(), val.month(), val.day()) + timedelta(seconds=time.timezone) - timedelta(hours=time.daylight)
 
650
                self.db.set_pubdate(id, dt)
595
651
            else:
596
652
                self.db.set(row, column, val)
597
653
            self.emit(SIGNAL("dataChanged(QModelIndex, QModelIndex)"), \
619
675
        TableView.__init__(self, parent)
620
676
        self.rating_delegate = LibraryDelegate(self)
621
677
        self.timestamp_delegate = DateDelegate(self)
 
678
        self.pubdate_delegate = PubDateDelegate(self)
 
679
        self.tags_delegate = TagsDelegate(self)
 
680
        self.authors_delegate = TextDelegate(self)
 
681
        self.series_delegate = TextDelegate(self)
 
682
        self.publisher_delegate = TextDelegate(self)
622
683
        self.display_parent = parent
623
684
        self._model = modelcls(self)
624
685
        self.setModel(self._model)
625
686
        self.setSelectionBehavior(QAbstractItemView.SelectRows)
626
687
        self.setSortingEnabled(True)
627
 
        try:
628
 
            self.columns_sorted(self._model.column_map.index('rating'),
629
 
                                self._model.column_map.index('timestamp'))
630
 
        except ValueError:
631
 
            pass
 
688
        for i in range(10):
 
689
            self.setItemDelegateForColumn(i, TextDelegate(self))
 
690
        self.columns_sorted()
632
691
        QObject.connect(self.selectionModel(), SIGNAL('currentRowChanged(QModelIndex, QModelIndex)'),
633
692
                        self._model.current_changed)
634
 
        self.connect(self._model, SIGNAL('columns_sorted(int, int)'), self.columns_sorted, Qt.QueuedConnection)
 
693
        self.connect(self._model, SIGNAL('columns_sorted()'),
 
694
                self.columns_sorted, Qt.QueuedConnection)
635
695
 
636
 
    def columns_sorted(self, rating_col, timestamp_col):
 
696
    def columns_sorted(self):
637
697
        for i in range(self.model().columnCount(None)):
638
698
            if self.itemDelegateForColumn(i) in (self.rating_delegate,
639
 
                    self.timestamp_delegate):
 
699
                    self.timestamp_delegate, self.pubdate_delegate):
640
700
                self.setItemDelegateForColumn(i, self.itemDelegate())
641
 
        if rating_col > -1:
642
 
            self.setItemDelegateForColumn(rating_col, self.rating_delegate)
643
 
        if timestamp_col > -1:
644
 
            self.setItemDelegateForColumn(timestamp_col, self.timestamp_delegate)
 
701
 
 
702
        cm = self._model.column_map
 
703
 
 
704
        if 'rating' in cm:
 
705
            self.setItemDelegateForColumn(cm.index('rating'), self.rating_delegate)
 
706
        if 'timestamp' in cm:
 
707
            self.setItemDelegateForColumn(cm.index('timestamp'), self.timestamp_delegate)
 
708
        if 'pubdate' in cm:
 
709
            self.setItemDelegateForColumn(cm.index('pubdate'), self.pubdate_delegate)
 
710
        if 'tags' in cm:
 
711
            self.setItemDelegateForColumn(cm.index('tags'), self.tags_delegate)
 
712
        if 'authors' in cm:
 
713
            self.setItemDelegateForColumn(cm.index('authors'), self.authors_delegate)
 
714
        if 'publisher' in cm:
 
715
            self.setItemDelegateForColumn(cm.index('publisher'), self.publisher_delegate)
 
716
        if 'series' in cm:
 
717
            self.setItemDelegateForColumn(cm.index('series'), self.series_delegate)
645
718
 
646
719
    def set_context_menu(self, edit_metadata, send_to_device, convert, view,
647
720
                         save, open_folder, book_details, similar_menu=None):
699
772
        paths = self.paths_from_event(event)
700
773
        event.setDropAction(Qt.CopyAction)
701
774
        event.accept()
702
 
        self.emit(SIGNAL('files_dropped(PyQt_PyObject)'), paths, Qt.QueuedConnection)
 
775
        self.emit(SIGNAL('files_dropped(PyQt_PyObject)'), paths)
703
776
 
704
777
 
705
778
    def set_database(self, db):
706
779
        self._model.set_database(db)
 
780
        self.tags_delegate.set_database(db)
 
781
        self.authors_delegate.set_auto_complete_function(db.all_authors)
 
782
        self.series_delegate.set_auto_complete_function(db.all_series)
 
783
        self.publisher_delegate.set_auto_complete_function(db.all_publishers)
707
784
 
708
785
    def close(self):
709
786
        self._model.close()
711
788
    def set_editable(self, editable):
712
789
        self._model.set_editable(editable)
713
790
 
714
 
    def connect_to_search_box(self, sb):
 
791
    def connect_to_search_box(self, sb, search_done):
715
792
        QObject.connect(sb, SIGNAL('search(PyQt_PyObject, PyQt_PyObject)'),
716
793
                        self._model.search)
 
794
        self._search_done = search_done
 
795
        self.connect(self._model, SIGNAL('searched(PyQt_PyObject)'),
 
796
                self.search_done)
717
797
 
718
798
    def connect_to_book_display(self, bd):
719
799
        QObject.connect(self._model, SIGNAL('new_bookdisplay_data(PyQt_PyObject)'),
720
800
                        bd)
721
801
 
 
802
    def search_done(self, ok):
 
803
        self._search_done(self, ok)
 
804
 
722
805
 
723
806
class DeviceBooksView(BooksView):
724
807
 
728
811
        self.resize_on_select = False
729
812
        self.rating_delegate = None
730
813
        for i in range(10):
731
 
            self.setItemDelegateForColumn(i, self.itemDelegate())
 
814
            self.setItemDelegateForColumn(i, TextDelegate(self))
732
815
        self.setDragDropMode(self.NoDragDrop)
733
816
        self.setAcceptDrops(False)
734
817
 
 
818
    def set_database(self, db):
 
819
        self._model.set_database(db)
 
820
 
735
821
    def resizeColumnsToContents(self):
736
822
        QTableView.resizeColumnsToContents(self)
737
823
        self.columns_resized = True
758
844
    def get_matches(self, location, query):
759
845
        location = location.lower().strip()
760
846
        query = query.lower().strip()
761
 
        if location not in ('title', 'authors', 'tags', 'all'):
 
847
        if location not in ('title', 'author', 'tag', 'all', 'format'):
762
848
            return set([])
763
849
        matches = set([])
764
 
        locations = ['title', 'authors', 'tags'] if location == 'all' else [location]
 
850
        locations = ['title', 'author', 'tag', 'format'] if location == 'all' else [location]
765
851
        q = {
766
852
             'title' : lambda x : getattr(x, 'title').lower(),
767
 
             'authors': lambda x: getattr(x, 'authors').lower(),
768
 
             'tags':lambda x: ','.join(getattr(x, 'tags')).lower()
 
853
             'author': lambda x: getattr(x, 'authors').lower(),
 
854
             'tag':lambda x: ','.join(getattr(x, 'tags')).lower(),
 
855
             'format':lambda x: os.path.splitext(x.path)[1].lower()
769
856
             }
770
857
        for i, v in enumerate(locations):
771
858
            locations[i] = q[v]
784
871
        self.db  = []
785
872
        self.map = []
786
873
        self.sorted_map = []
787
 
        self.unknown = str(self.trUtf8('Unknown'))
 
874
        self.unknown = _('Unknown')
788
875
        self.marked_for_deletion = {}
789
876
        self.search_engine = OnDeviceSearch(self)
790
877
        self.editable = True
829
916
        if not text or not text.strip():
830
917
            self.map = list(range(len(self.db)))
831
918
        else:
832
 
            matches = self.search_engine.parse(text)
 
919
            try:
 
920
                matches = self.search_engine.parse(text)
 
921
            except ParseException:
 
922
                self.emit(SIGNAL('searched(PyQt_PyObject)'), False)
 
923
                return
 
924
 
833
925
            self.map = []
834
926
            for i in range(len(self.db)):
835
927
                if i in matches:
838
930
        if reset:
839
931
            self.reset()
840
932
        self.last_search = text
 
933
        if self.last_search:
 
934
            self.emit(SIGNAL('searched(PyQt_PyObject)'), True)
 
935
 
841
936
 
842
937
    def resort(self, reset):
843
938
        self.sort(self.sorted_on[0], self.sorted_on[1], reset=reset)
1013
1108
        QLineEdit.__init__(self, parent)
1014
1109
        self.help_text = help_text
1015
1110
        self.initial_state = True
 
1111
        self.as_you_type = True
1016
1112
        self.default_palette = QApplication.palette(self)
1017
1113
        self.gray = QPalette(self.default_palette)
1018
1114
        self.gray.setBrush(QPalette.Text, QBrush(QColor('gray')))
1031
1127
        self.setText(self.help_text)
1032
1128
        self.home(False)
1033
1129
        self.initial_state = True
 
1130
        self.setStyleSheet("background-color: white")
 
1131
        self.emit(SIGNAL('cleared()'))
1034
1132
 
1035
1133
    def clear(self):
1036
1134
        self.clear_to_help()
1037
1135
        self.emit(SIGNAL('search(PyQt_PyObject, PyQt_PyObject)'), '', False)
1038
1136
 
 
1137
    def search_done(self, ok):
 
1138
        col = 'rgba(0,255,0,25%)' if ok else 'rgb(255,0,0,25%)'
 
1139
        self.setStyleSheet('background-color: '+col)
1039
1140
 
1040
1141
    def keyPressEvent(self, event):
1041
1142
        if self.initial_state:
1042
1143
            self.normalize_state()
1043
1144
            self.initial_state = False
 
1145
        if not self.as_you_type:
 
1146
            if event.key() in (Qt.Key_Return, Qt.Key_Enter):
 
1147
                self.do_search()
1044
1148
        QLineEdit.keyPressEvent(self, event)
1045
1149
 
1046
1150
    def mouseReleaseEvent(self, event):
1050
1154
        QLineEdit.mouseReleaseEvent(self, event)
1051
1155
 
1052
1156
    def text_edited_slot(self, text):
1053
 
        text = qstring_to_unicode(text) if isinstance(text, QString) else unicode(text)
1054
 
        self.prev_text = text
1055
 
        self.timer = self.startTimer(self.__class__.INTERVAL)
 
1157
        if self.as_you_type:
 
1158
            text = qstring_to_unicode(text) if isinstance(text, QString) else unicode(text)
 
1159
            self.prev_text = text
 
1160
            self.timer = self.startTimer(self.__class__.INTERVAL)
1056
1161
 
1057
1162
    def timerEvent(self, event):
1058
1163
        self.killTimer(event.timerId())
1059
1164
        if event.timerId() == self.timer:
1060
 
            text = qstring_to_unicode(self.text())
1061
 
            refinement = text.startswith(self.prev_search) and ':' not in text
1062
 
            self.prev_search = text
1063
 
            self.emit(SIGNAL('search(PyQt_PyObject, PyQt_PyObject)'), text, refinement)
 
1165
            self.do_search()
 
1166
 
 
1167
    def do_search(self):
 
1168
        text = qstring_to_unicode(self.text())
 
1169
        refinement = text.startswith(self.prev_search) and ':' not in text
 
1170
        self.prev_search = text
 
1171
        self.emit(SIGNAL('search(PyQt_PyObject, PyQt_PyObject)'), text, refinement)
1064
1172
 
1065
1173
    def search_from_tokens(self, tokens, all):
1066
1174
        ans = u' '.join([u'%s:%s'%x for x in tokens])
1078
1186
        self.emit(SIGNAL('search(PyQt_PyObject, PyQt_PyObject)'), txt, False)
1079
1187
        self.end(False)
1080
1188
        self.initial_state = False
 
1189
 
 
1190
    def search_as_you_type(self, enabled):
 
1191
        self.as_you_type = enabled
 
1192