diff --git a/src/calibre/gui2/__init__.py b/src/calibre/gui2/__init__.py index a833aee8c0..c67c8e5ca4 100644 --- a/src/calibre/gui2/__init__.py +++ b/src/calibre/gui2/__init__.py @@ -13,7 +13,6 @@ from PyQt4.QtGui import QFileDialog, QMessageBox, QPixmap, QFileIconProvider, \ ORG_NAME = 'KovidsBrain' APP_UID = 'libprs500' from calibre import islinux, iswindows, isosx, isfreebsd -from calibre.constants import preferred_encoding from calibre.utils.config import Config, ConfigProxy, dynamic, JSONConfig from calibre.utils.localization import set_qt_translator from calibre.ebooks.metadata.meta import get_metadata, metadata_from_formats diff --git a/src/calibre/gui2/dialogs/comments_dialog.py b/src/calibre/gui2/dialogs/comments_dialog.py index f9806b44d1..8b4df07fbc 100644 --- a/src/calibre/gui2/dialogs/comments_dialog.py +++ b/src/calibre/gui2/dialogs/comments_dialog.py @@ -7,6 +7,7 @@ from PyQt4.Qt import QDialog from calibre.gui2.dialogs.comments_dialog_ui import Ui_CommentsDialog class CommentsDialog(QDialog, Ui_CommentsDialog): + def __init__(self, parent, text): QDialog.__init__(self, parent) Ui_CommentsDialog.__init__(self) diff --git a/src/calibre/gui2/library.py b/src/calibre/gui2/library.py index f499c95e14..9f209a0066 100644 --- a/src/calibre/gui2/library.py +++ b/src/calibre/gui2/library.py @@ -29,7 +29,7 @@ from calibre.utils.date import dt_factory, qt_to_dt, isoformat from calibre.utils.pyparsing import ParseException from calibre.utils.search_query_parser import SearchQueryParser -class LibraryDelegate(QStyledItemDelegate): +class RatingDelegate(QStyledItemDelegate): COLOR = QColor("blue") SIZE = 16 PEN = QPen(COLOR, 1, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin) @@ -162,17 +162,16 @@ class TagsDelegate(QStyledItemDelegate): editor = TagsLineEdit(parent, self.db.all_tags()) else: editor = TagsLineEdit(parent, sorted(list(self.db.all_custom(label=col)))) - return editor; + return editor else: editor = EnLineEdit(parent) return editor class CcTextDelegate(QStyledItemDelegate): - def __init__(self, parent): - ''' - Delegate for text/int/float data. - ''' - QStyledItemDelegate.__init__(self, parent) + ''' + Delegate for text/int/float data. + ''' + def createEditor(self, parent, option, index): m = index.model() col = m.column_map[index.column()] @@ -191,12 +190,9 @@ class CcTextDelegate(QStyledItemDelegate): return editor class CcCommentsDelegate(QStyledItemDelegate): - def __init__(self, parent): - ''' - Delegate for comments data. - ''' - QStyledItemDelegate.__init__(self, parent) - self.parent = parent + ''' + Delegate for comments data. + ''' def createEditor(self, parent, option, index): m = index.model() @@ -211,7 +207,7 @@ class CcCommentsDelegate(QStyledItemDelegate): return None def setModelData(self, editor, model, index): - model.setData(index, QVariant(editor.textbox.text()), Qt.EditRole) + model.setData(index, QVariant(editor.textbox.toPlainText()), Qt.EditRole) class CcBoolDelegate(QStyledItemDelegate): def __init__(self, parent): @@ -247,6 +243,7 @@ class BooksModel(QAbstractTableModel): about_to_be_sorted = pyqtSignal(object, name='aboutToBeSorted') sorting_done = pyqtSignal(object, name='sortingDone') + database_changed = pyqtSignal(object, name='databaseChanged') orig_headers = { 'title' : _("Title"), @@ -304,6 +301,7 @@ class BooksModel(QAbstractTableModel): self.db = db self.custom_columns = self.db.custom_column_label_map self.read_config() + self.database_changed.emit(db) def refresh_ids(self, ids, current_row=-1): rows = self.db.refresh_ids(ids) @@ -893,7 +891,7 @@ class BooksView(TableView): def __init__(self, parent, modelcls=BooksModel): TableView.__init__(self, parent) - self.rating_delegate = LibraryDelegate(self) + self.rating_delegate = RatingDelegate(self) self.timestamp_delegate = DateDelegate(self) self.pubdate_delegate = PubDateDelegate(self) self.tags_delegate = TagsDelegate(self) diff --git a/src/calibre/gui2/main.ui b/src/calibre/gui2/main.ui index 73cee4a061..2021e1bc88 100644 --- a/src/calibre/gui2/main.ui +++ b/src/calibre/gui2/main.ui @@ -301,17 +301,14 @@ - - + + + Qt::Horizontal + + - - - 256 - 16777215 - - true @@ -354,12 +351,12 @@ - - Manage user categories + + Create, edit, and delete user categories + + + Manage &user categories - - Create, edit, and delete user categories - @@ -369,7 +366,10 @@ - Restrict display to: + &Restrict to: + + + search_restriction @@ -381,50 +381,48 @@ 0 - - Books display will be restricted to those matching the selected saved search - + + Books display will be restricted to those matching the selected saved search + - - - - - - 100 - 10 - - - - true - - - true - - - false - - - QAbstractItemView::DragDrop - - - true - - - QAbstractItemView::SelectRows - - - false - - - false - - - - + + + + + 100 + 10 + + + + true + + + true + + + false + + + QAbstractItemView::DragDrop + + + true + + + QAbstractItemView::SelectRows + + + false + + + false + + + diff --git a/src/calibre/gui2/status.py b/src/calibre/gui2/status.py index bdba768c5f..371efddb44 100644 --- a/src/calibre/gui2/status.py +++ b/src/calibre/gui2/status.py @@ -205,19 +205,6 @@ class CoverFlowButton(QToolButton): self.setDisabled(True) self.setToolTip(_('

Browsing books by their covers is disabled.
Import of pictureflow module failed:
')+reason) -class TagViewButton(QToolButton): - - def __init__(self, parent=None): - QToolButton.__init__(self, parent) - self.setIconSize(QSize(80, 80)) - self.setIcon(QIcon(I('tags.svg'))) - self.setToolTip(_('Click to browse books by tags')) - self.setSizePolicy(QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Expanding)) - self.setCursor(Qt.PointingHandCursor) - self.setCheckable(True) - self.setChecked(False) - self.setAutoRaise(True) - class StatusBar(QStatusBar): @@ -227,9 +214,7 @@ class StatusBar(QStatusBar): self.notifier = get_notifier(systray) self.movie_button = MovieButton(jobs_dialog) self.cover_flow_button = CoverFlowButton() - self.tag_view_button = TagViewButton() self.addPermanentWidget(self.cover_flow_button) - self.addPermanentWidget(self.tag_view_button) self.addPermanentWidget(self.movie_button) self.book_info = BookInfoDisplay(self.clearMessage) self.book_info.setAcceptDrops(True) diff --git a/src/calibre/gui2/ui.py b/src/calibre/gui2/ui.py index d5f50b92b8..6e0c5e333f 100644 --- a/src/calibre/gui2/ui.py +++ b/src/calibre/gui2/ui.py @@ -575,8 +575,6 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI): self.connect(self.tags_view, SIGNAL('tags_marked(PyQt_PyObject, PyQt_PyObject)'), self.saved_search.clear_to_help) - self.connect(self.status_bar.tag_view_button, - SIGNAL('toggled(bool)'), self.toggle_tags_view) self.connect(self.search, SIGNAL('search(PyQt_PyObject, PyQt_PyObject)'), self.tags_view.model().reinit) @@ -602,6 +600,14 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI): self.db_images.reset() self.library_view.model().count_changed() + self.location_view.model().database_changed(self.library_view.model().db) + self.library_view.model().database_changed.connect(self.location_view.model().database_changed, + type=Qt.QueuedConnection) + + ########################### Tags Browser ############################## + self.search_restriction.setSizeAdjustPolicy(self.search_restriction.AdjustToMinimumContentsLengthWithIcon) + self.search_restriction.setMinimumContentsLength(10) + ########################### Cover Flow ################################ self.cover_flow = None @@ -666,8 +672,10 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI): if self.cover_flow is not None and dynamic.get('cover_flow_visible', False): self.status_bar.cover_flow_button.toggle() - if dynamic.get('tag_view_visible', False): - self.status_bar.tag_view_button.toggle() + tb_state = dynamic.get('tag_browser_state', None) + if tb_state is not None: + self.horizontal_splitter.restoreState(tb_state) + self.toggle_tags_view(True) self._add_filesystem_book = Dispatcher(self.__add_filesystem_book) v = self.library_view @@ -2323,7 +2331,6 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI): self.view_menu.actions()[1].setEnabled(True) self.action_open_containing_folder.setEnabled(True) self.action_sync.setEnabled(True) - self.status_bar.tag_view_button.setEnabled(True) self.status_bar.cover_flow_button.setEnabled(True) for action in list(self.delete_menu.actions())[1:]: action.setEnabled(True) @@ -2334,7 +2341,6 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI): self.view_menu.actions()[1].setEnabled(False) self.action_open_containing_folder.setEnabled(False) self.action_sync.setEnabled(False) - self.status_bar.tag_view_button.setEnabled(False) self.status_bar.cover_flow_button.setEnabled(False) for action in list(self.delete_menu.actions())[1:]: action.setEnabled(False) @@ -2451,8 +2457,9 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI): def write_settings(self): config.set('main_window_geometry', self.saveGeometry()) dynamic.set('sort_history', self.library_view.model().sort_history) - dynamic.set('tag_view_visible', self.tags_view.isVisible()) dynamic.set('cover_flow_visible', self.cover_flow.isVisible()) + dynamic.set('tag_browser_state', + str(self.horizontal_splitter.saveState())) self.library_view.write_settings() if self.device_connected: self.save_device_view_settings() diff --git a/src/calibre/gui2/widgets.py b/src/calibre/gui2/widgets.py index 586966d94f..c48ded1dc2 100644 --- a/src/calibre/gui2/widgets.py +++ b/src/calibre/gui2/widgets.py @@ -23,6 +23,7 @@ from calibre.ebooks import BOOK_EXTENSIONS from calibre.ebooks.metadata.meta import metadata_from_filename from calibre.utils.config import prefs, XMLConfig from calibre.gui2.progress_indicator import ProgressIndicator as _ProgressIndicator +from calibre.constants import filesystem_encoding history = XMLConfig('history') @@ -230,13 +231,22 @@ class LocationModel(QAbstractListModel): self.free = [-1, -1, -1] self.count = 0 self.highlight_row = 0 + self.library_tooltip = _('Click to see the books available on your computer') self.tooltips = [ - _('Click to see the books available on your computer'), + self.library_tooltip, _('Click to see the books in the main memory of your reader'), _('Click to see the books on storage card A in your reader'), _('Click to see the books on storage card B in your reader') ] + def database_changed(self, db): + lp = db.library_path + if not isinstance(lp, unicode): + lp = lp.decode(filesystem_encoding, 'replace') + self.tooltips[0] = self.library_tooltip + '\n\n' + \ + _('Books located at') + ' ' + lp + self.dataChanged.emit(self.index(0), self.index(0)) + def rowCount(self, *args): return 1 + len([i for i in self.free if i >= 0]) diff --git a/src/calibre/library/caches.py b/src/calibre/library/caches.py index a31a8a846c..ee19f07644 100644 --- a/src/calibre/library/caches.py +++ b/src/calibre/library/caches.py @@ -155,7 +155,9 @@ class ResultCache(SearchQueryParser): self._map = self._map_filtered = self._data = [] self.first_sort = True self.search_restriction = '' - SearchQueryParser.__init__(self, [c for c in cc_label_map]) + SearchQueryParser.__init__(self, + locations=SearchQueryParser.DEFAULT_LOCATIONS + + [c for c in cc_label_map]) self.build_relop_dict() def build_relop_dict(self): diff --git a/src/calibre/utils/search_query_parser.py b/src/calibre/utils/search_query_parser.py index 6768b66063..79324e6b8b 100644 --- a/src/calibre/utils/search_query_parser.py +++ b/src/calibre/utils/search_query_parser.py @@ -73,7 +73,7 @@ class SearchQueryParser(object): When no operator is specified between two tokens, `and` is assumed. Each token is a string of the form `location:query`. `location` is a string - from :member:`LOCATIONS`. It is optional. If it is omitted, it is assumed to + from :member:`DEFAULT_LOCATIONS`. It is optional. If it is omitted, it is assumed to be `all`. `query` is an arbitrary string that must not contain parentheses. If it contains whitespace, it should be quoted by enclosing it in `"` marks. @@ -86,7 +86,7 @@ class SearchQueryParser(object): * `(author:Asimov or author:Hardy) and not tag:read` [search for unread books by Asimov or Hardy] ''' - LOCATIONS = [ + DEFAULT_LOCATIONS = [ 'tag', 'title', 'author', @@ -116,10 +116,13 @@ class SearchQueryParser(object): failed.append(test[0]) return failed - def __init__(self, custcols=[], test=False): + def __init__(self, locations=None, test=False): + if locations is None: + locations = self.DEFAULT_LOCATIONS self._tests_failed = False # Define a token - standard_locations = map(lambda x : CaselessLiteral(x)+Suppress(':'), self.LOCATIONS+custcols) + standard_locations = map(lambda x : CaselessLiteral(x)+Suppress(':'), + locations) location = NoMatch() for l in standard_locations: location |= l @@ -228,7 +231,7 @@ class SearchQueryParser(object): ''' Should return the set of matches for :param:'location` and :param:`query`. - :param:`location` is one of the items in :member:`SearchQueryParser.LOCATIONS`. + :param:`location` is one of the items in :member:`SearchQueryParser.DEFAULT_LOCATIONS`. :param:`query` is a string literal. ''' return set([]) diff --git a/src/calibre/web/feeds/recipes/model.py b/src/calibre/web/feeds/recipes/model.py index 55ff51d1e9..4eea0ce80c 100644 --- a/src/calibre/web/feeds/recipes/model.py +++ b/src/calibre/web/feeds/recipes/model.py @@ -121,7 +121,7 @@ class RecipeModel(QAbstractItemModel, SearchQueryParser): def __init__(self, db, *args): QAbstractItemModel.__init__(self, *args) - SearchQueryParser.__init__(self) + SearchQueryParser.__init__(self, locations=['all']) self.db = db self.default_icon = QVariant(QIcon(I('news.svg'))) self.custom_icon = QVariant(QIcon(I('user_profile.svg')))