diff --git a/src/calibre/gui2/main.ui b/src/calibre/gui2/main.ui
index 5d564b5f0c..9ad7dbcc49 100644
--- a/src/calibre/gui2/main.ui
+++ b/src/calibre/gui2/main.ui
@@ -696,7 +696,7 @@
TagsView
QTreeView
-
+
diff --git a/src/calibre/gui2/tag_view.py b/src/calibre/gui2/tag_view.py
new file mode 100644
index 0000000000..7d9f435fa9
--- /dev/null
+++ b/src/calibre/gui2/tag_view.py
@@ -0,0 +1,151 @@
+#!/usr/bin/env python
+__license__ = 'GPL v3'
+__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
+__docformat__ = 'restructuredtext en'
+
+'''
+Browsing book collection by tags.
+'''
+from PyQt4.Qt import QStandardItemModel, Qt, QTreeView, QStandardItem, \
+ QFont, SIGNAL, QSize, QIcon, QPoint, QPixmap
+from calibre.gui2 import config
+
+class TagsView(QTreeView):
+
+ def __init__(self, *args):
+ QTreeView.__init__(self, *args)
+ self.setUniformRowHeights(True)
+ self.setCursor(Qt.PointingHandCursor)
+ self.setIconSize(QSize(30, 30))
+
+ def set_database(self, db, match_all, popularity):
+ self._model = TagsModel(db)
+ self.popularity = popularity
+ self.match_all = match_all
+ self.setModel(self._model)
+ self.connect(self, SIGNAL('clicked(QModelIndex)'), self.toggle)
+ self.popularity.setChecked(config['sort_by_popularity'])
+ self.connect(self.popularity, SIGNAL('stateChanged(int)'), self.sort_changed)
+
+ def sort_changed(self, state):
+ config.set('sort_by_popularity', state == Qt.Checked)
+ self.model().refresh()
+
+ def toggle(self, index):
+ if self._model.toggle(index):
+ self.emit(SIGNAL('tags_marked(PyQt_PyObject, PyQt_PyObject)'),
+ self._model.tokens(), self.match_all.isChecked())
+
+ def recount(self, *args):
+ ci = self.currentIndex()
+ if not ci.isValid():
+ ci = self.indexAt(QPoint(10, 10))
+ self.model().refresh()
+ if ci.isValid():
+ self.scrollTo(ci, QTreeView.PositionAtTop)
+
+class CategoryItem(QStandardItem):
+
+ def __init__(self, category, display_text, tags, icon, font, icon_map):
+ self.category = category
+ self.tags = tags
+ QStandardItem.__init__(self, icon, display_text)
+ self.setFont(font)
+ self.setSelectable(False)
+ self.setSizeHint(QSize(100, 40))
+ self.setEditable(False)
+ for tag in tags:
+ self.appendRow(TagItem(tag, icon_map))
+
+class TagItem(QStandardItem):
+
+ def __init__(self, tag, icon_map):
+ self.icon_map = icon_map
+ self.tag = tag
+ QStandardItem.__init__(self, tag.as_string())
+ self.set_icon()
+ self.setEditable(False)
+ self.setSelectable(False)
+
+ def toggle(self):
+ self.tag.state = (self.tag.state + 1)%3
+ self.set_icon()
+
+ def set_icon(self):
+ self.setIcon(self.icon_map[self.tag.state])
+
+
+class TagsModel(QStandardItemModel):
+
+ categories = [_('Authors'), _('Series'), _('Formats'), _('Publishers'), _('News'), _('Tags')]
+ row_map = ['author', 'series', 'format', 'publisher', 'news', 'tag']
+
+ def __init__(self, db):
+ self.cmap = tuple(map(QIcon, [':/images/user_profile.svg',
+ ':/images/series.svg', ':/images/book.svg', ':/images/publisher.png',
+ ':/images/news.svg', ':/images/tags.svg']))
+ p = QPixmap(30, 30)
+ p.fill(Qt.transparent)
+ self.icon_map = [QIcon(p), QIcon(':/images/plus.svg'),
+ QIcon(':/images/minus.svg')]
+ QStandardItemModel.__init__(self)
+ self.db = db
+ self.ignore_next_search = False
+ self._data = {}
+ self.bold_font = QFont()
+ self.bold_font.setBold(True)
+ self.refresh()
+ self.db.add_listener(self.database_changed)
+
+ def database_changed(self, event, ids):
+ self.refresh()
+
+ def refresh(self):
+ old_data = self._data
+ self._data = self.db.get_categories(config['sort_by_popularity'])
+ for key in old_data.keys():
+ for tag in old_data[key]:
+ try:
+ index = self._data[key].index(tag)
+ if index > -1:
+ self._data[key][index].state = tag.state
+ except:
+ continue
+ self.clear()
+ root = self.invisibleRootItem()
+ for r, category in enumerate(self.row_map):
+ tags = self._data.get(category, [])
+ root.appendRow(CategoryItem(category, self.categories[r],
+ self._data[category], self.cmap[r], self.bold_font, self.icon_map))
+ #self.reset()
+
+
+ def reinit(self, *args, **kwargs):
+ if not self.ignore_next_search:
+ for category in self._data.values():
+ for tag in category:
+ tag.state = 0
+ self.reset()
+ self.ignore_next_search = False
+
+ def toggle(self, index):
+ if index.parent().isValid():
+ category = self.row_map[index.parent().row()]
+ tag = self._data[category][index.row()]
+ self.invisibleRootItem().child(index.parent().row()).child(index.row()).toggle()
+ self.ignore_next_search = True
+ self.emit(SIGNAL('dataChanged(QModelIndex,QModelIndex)'), index, index)
+ return True
+ return False
+
+ def tokens(self):
+ ans = []
+ for key in self.row_map:
+ for tag in self._data[key]:
+ category = key if key != 'news' else 'tag'
+ if tag.state > 0:
+ prefix = ' not ' if tag.state == 2 else ''
+ ans.append('%s%s:"%s"'%(prefix, category, tag))
+ return ans
+
+
diff --git a/src/calibre/gui2/tags.py b/src/calibre/gui2/tags.py
deleted file mode 100644
index a6772a3b44..0000000000
--- a/src/calibre/gui2/tags.py
+++ /dev/null
@@ -1,173 +0,0 @@
-#!/usr/bin/env python
-__license__ = 'GPL v3'
-__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
-__docformat__ = 'restructuredtext en'
-
-'''
-Browsing book collection by tags.
-'''
-from PyQt4.Qt import QAbstractItemModel, Qt, QVariant, QTreeView, QModelIndex, \
- QFont, SIGNAL, QSize, QColor, QIcon, QPoint
-from calibre.gui2 import config
-NONE = QVariant()
-
-class TagsView(QTreeView):
-
- def __init__(self, *args):
- QTreeView.__init__(self, *args)
- self.setUniformRowHeights(True)
- self.setCursor(Qt.PointingHandCursor)
- self.setIconSize(QSize(30, 30))
-
- def set_database(self, db, match_all, popularity):
- self._model = TagsModel(db)
- self.popularity = popularity
- self.match_all = match_all
- self.setModel(self._model)
- self.connect(self, SIGNAL('clicked(QModelIndex)'), self.toggle)
- self.popularity.setChecked(config['sort_by_popularity'])
- self.connect(self.popularity, SIGNAL('stateChanged(int)'), self.sort_changed)
-
- def sort_changed(self, state):
- config.set('sort_by_popularity', state == Qt.Checked)
- self.model().refresh()
-
- def toggle(self, index):
- if self._model.toggle(index):
- self.emit(SIGNAL('tags_marked(PyQt_PyObject, PyQt_PyObject)'),
- self._model.tokens(), self.match_all.isChecked())
-
- def recount(self, *args):
- ci = self.currentIndex()
- if not ci.isValid():
- ci = self.indexAt(QPoint(10, 10))
- self.model().refresh()
- if ci.isValid():
- self.scrollTo(ci, QTreeView.PositionAtTop)
-
-class TagsModel(QAbstractItemModel):
-
- categories = [_('Authors'), _('Series'), _('Formats'), _('Publishers'), _('News'), _('Tags')]
- row_map = {0: 'author', 1:'series', 2:'format', 3:'publisher', 4:'news', 5:'tag'}
-
- def __init__(self, db):
- QAbstractItemModel.__init__(self)
- self.db = db
- self.ignore_next_search = False
- self._data = {}
- self.refresh()
- self.bold_font = QFont()
- self.bold_font.setBold(True)
- self.bold_font = QVariant(self.bold_font)
- self.status_map = [QColor(200,200,200, 0), QIcon(':/images/plus.svg'), QIcon(':/images/minus.svg')]
- self.status_map = list(map(QVariant, self.status_map))
- self.cmap = [QIcon(':/images/user_profile.svg'), QIcon(':/images/series.svg'), QIcon(':/images/book.svg'), QIcon(':/images/publisher.png'), QIcon(':/images/news.svg'), QIcon(':/images/tags.svg')]
- self.cmap = list(map(QVariant, self.cmap))
- self.db.add_listener(self.database_changed)
-
- def database_changed(self, event, ids):
- self.refresh()
-
- def refresh(self):
- old_data = self._data
- self._data = self.db.get_categories(config['sort_by_popularity'])
- for key in old_data.keys():
- for tag in old_data[key]:
- try:
- index = self._data[key].index(tag)
- if index > -1:
- self._data[key][index].state = tag.state
- except:
- continue
- self.reset()
-
- def reinit(self, *args, **kwargs):
- if not self.ignore_next_search:
- for category in self._data.values():
- for tag in category:
- tag.state = 0
- self.reset()
- self.ignore_next_search = False
-
- def toggle(self, index):
- if index.parent().isValid():
- category = self.row_map[index.parent().row()]
- tag = self._data[category][index.row()]
- tag.state = (tag.state + 1)%3
- self.ignore_next_search = True
- self.emit(SIGNAL('dataChanged(QModelIndex,QModelIndex)'), index, index)
- return True
- return False
-
- def tokens(self):
- ans = []
- for key in self.row_map.values():
- for tag in self._data[key]:
- category = key if key != 'news' else 'tag'
- if tag.state > 0:
- prefix = ' not ' if tag.state == 2 else ''
- ans.append('%s%s:"%s"'%(prefix, category, tag))
- return ans
-
- def index(self, row, col, parent=QModelIndex()):
- if parent.isValid():
- if parent.parent().isValid(): # parent is a tag
- return QModelIndex()
- try:
- category = self.row_map[parent.row()]
- except KeyError:
- return QModelIndex()
- if col == 0 and row < len(self._data[category]):
- return self.createIndex(row, col, parent.row())
- return QModelIndex()
- if col == 0 and row < len(self.categories):
- return self.createIndex(row, col, -1)
- return QModelIndex()
-
- def parent(self, index):
- if not index.isValid() or index.internalId() < 0:
- return QModelIndex()
- return self.createIndex(index.internalId(), 0, -1)
-
- def rowCount(self, parent):
- if not parent or not parent.isValid():
- return len(self.categories)
- if not parent.parent().isValid():
- return len(self._data[self.row_map[parent.row()]])
- return 0
-
- def columnCount(self, parent):
- return 1
-
- def flags(self, index):
- if not index.isValid():
- return Qt.NoItemFlags
- return Qt.ItemIsEnabled
-
- def category_data(self, index, role):
- if role == Qt.DisplayRole:
- row = index.row()
- return QVariant(self.categories[row])
- if role == Qt.FontRole:
- return self.bold_font
- if role == Qt.SizeHintRole:
- return QVariant(QSize(100, 40))
- if role == Qt.DecorationRole:
- return self.cmap[index.row()]
- return NONE
-
- def tag_data(self, index, role):
- category = self.row_map[index.parent().row()]
- if role == Qt.DisplayRole:
- return QVariant(self._data[category][index.row()].as_string())
- if role == Qt.DecorationRole:
- return self.status_map[self._data[category][index.row()].state]
- return NONE
-
-
- def data(self, index, role):
- if not index.parent().isValid():
- return self.category_data(index, role)
- if not index.parent().parent().isValid():
- return self.tag_data(index, role)
- return NONE
diff --git a/src/calibre/linux.py b/src/calibre/linux.py
index 34f7abb195..11884a2e4e 100644
--- a/src/calibre/linux.py
+++ b/src/calibre/linux.py
@@ -334,7 +334,9 @@ def post_install():
os.chdir(config_dir)
for f in os.listdir('.'):
if os.stat(f).st_uid == 0:
- os.unlink(f)
+ os.rmdir(f) if os.path.isdir(f) else os.unlink(f)
+ if os.stat(config_dir).st_uid == 0:
+ os.rmdir(config_dir)
def binary_install():
manifest = os.path.join(getattr(sys, 'frozen_path'), 'manifest')