1. added context menu on tags pane.

2. added saved search editor
3l added tags editor (a cut-down version of the original)
4. added access to editors from context menu.
This commit is contained in:
Charles Haley 2010-06-02 13:19:28 +01:00
parent c80e12c5a2
commit 26f5642e02
8 changed files with 597 additions and 28 deletions

View File

@ -97,7 +97,8 @@ def _config():
help=_('Overwrite author and title with new metadata'))
c.add_opt('enforce_cpu_limit', default=True,
help=_('Limit max simultaneous jobs to number of CPUs'))
c.add_opt('tag_browser_hidden_categories', default=set(),
help=_('tag browser categories not to display'))
return ConfigProxy(c)
config = _config()

View File

@ -0,0 +1,86 @@
__license__ = 'GPL v3'
__copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
from PyQt4.QtCore import SIGNAL, Qt
from PyQt4.QtGui import QDialog, QIcon, QListWidgetItem
from calibre.gui2.dialogs.saved_search_editor_ui import Ui_SavedSearchEditor
from calibre.utils.config import prefs
from calibre.utils.search_query_parser import saved_searches
from calibre.gui2.dialogs.confirm_delete import confirm
from calibre.constants import islinux
class SavedSearchEditor(QDialog, Ui_SavedSearchEditor):
def __init__(self, window, initial_search=None):
QDialog.__init__(self, window)
Ui_SavedSearchEditor.__init__(self)
self.setupUi(self)
self.connect(self.add_search_button, SIGNAL('clicked()'), self.add_search)
self.connect(self.search_name_box, SIGNAL('currentIndexChanged(int)'),
self.current_index_changed)
self.connect(self.delete_search_button, SIGNAL('clicked()'), self.del_search)
self.current_search_name = None
self.searches = {}
self.searches_to_delete = []
for name in saved_searches.names():
self.searches[name] = saved_searches.lookup(name)
self.populate_search_list()
if initial_search is not None and initial_search in self.searches:
self.select_search(initial_search)
def populate_search_list(self):
self.search_name_box.clear()
for name in sorted(self.searches.keys()):
self.search_name_box.addItem(name)
def add_search(self):
search_name = unicode(self.input_box.text()).strip()
if search_name == '':
return False
if search_name not in self.searches:
self.searches[search_name] = ''
self.populate_search_list()
self.select_search(search_name)
else:
self.select_search(search_name)
return True
def del_search(self):
if self.current_search_name is not None:
if not confirm('<p>'+_('The current saved search will be '
'<b>permanently deleted</b>. Are you sure?')
+'</p>', 'saved_search_editor_delete', self):
return
del self.searches[self.current_search_name]
self.searches_to_delete.append(self.current_search_name)
self.current_search_name = None
self.search_name_box.removeItem(self.search_name_box.currentIndex())
def select_search(self, name):
self.search_name_box.setCurrentIndex(self.search_name_box.findText(name))
def current_index_changed(self, idx):
if self.current_search_name:
self.searches[self.current_search_name] = unicode(self.search_text.toPlainText())
name = unicode(self.search_name_box.itemText(idx))
if name:
self.current_search_name = name
self.search_text.setPlainText(self.searches[name])
else:
self.current_search_name = None
self.search_text.setPlainText('')
def accept(self):
if self.current_search_name:
self.searches[self.current_search_name] = unicode(self.search_text.toPlainText())
for name in self.searches_to_delete:
saved_searches.delete(name)
for name in self.searches:
saved_searches.add(name, self.searches[name])
QDialog.accept(self)

View File

@ -0,0 +1,181 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>SavedSearchEditor</class>
<widget class="QDialog" name="SavedSearchEditor">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>548</width>
<height>148</height>
</rect>
</property>
<property name="windowTitle">
<string>Tag Editor</string>
</property>
<property name="windowIcon">
<iconset>
<normaloff>:/images/chapters.svg</normaloff>:/images/chapters.svg</iconset>
</property>
<layout class="QGridLayout">
<item row="2" column="0" colspan="2">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
<property name="centerButtons">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="0" colspan="2">
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="label_3">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Saved Search: </string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>search_name_box</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="search_name_box">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>160</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>145</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Select a saved search to edit</string>
</property>
<property name="editable">
<bool>false</bool>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QToolButton" name="delete_search_button">
<property name="toolTip">
<string>Delete this selected saved search</string>
</property>
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset>
<normaloff>:/images/minus.svg</normaloff>:/images/minus.svg</iconset>
</property>
</widget>
</item>
<item row="0" column="3">
<spacer>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="4">
<widget class="QLineEdit" name="input_box">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>60</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Enter a new saved search name.</string>
</property>
</widget>
</item>
<item row="0" column="5">
<widget class="QToolButton" name="add_search_button">
<property name="toolTip">
<string>Add the new saved search</string>
</property>
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset>
<normaloff>:/images/plus.svg</normaloff>:/images/plus.svg</iconset>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="0">
<widget class="QPlainTextEdit" name="search_text"/>
</item>
</layout>
</widget>
<resources>
<include location="../../../../../calibre_datesearch/resources/images"/>
</resources>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>SavedSearchEditor</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>SavedSearchEditor</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -24,13 +24,12 @@ class Item:
class TagCategories(QDialog, Ui_TagCategories):
category_labels_orig = ['', 'authors', 'series', 'publishers', 'tags']
def __init__(self, window, db, index=None):
def __init__(self, window, db, on_category=None):
QDialog.__init__(self, window)
Ui_TagCategories.__init__(self)
self.setupUi(self)
self.db = db
self.index = index
self.applied_items = []
cc_icon = QIcon(I('column.svg'))
@ -102,8 +101,10 @@ class TagCategories(QDialog, Ui_TagCategories):
self.connect(self.applied_items_box, SIGNAL('itemActivated(QListWidgetItem*)'), self.unapply_tags)
self.populate_category_list()
return
self.select_category(0)
if on_category is not None:
l = self.category_box.findText(on_category)
if l >= 0:
self.category_box.setCurrentIndex(l)
def make_list_widget(self, item):
n = item.name if item.exists else item.name + _(' (not on any book)')

View File

@ -0,0 +1,55 @@
__license__ = 'GPL v3'
__copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
from PyQt4.QtCore import SIGNAL
from PyQt4.QtGui import QDialog
from calibre.gui2.dialogs.tag_list_editor_ui import Ui_TagListEditor
from calibre.gui2 import question_dialog, error_dialog
class TagListEditor(QDialog, Ui_TagListEditor):
def tag_cmp(self, x, y):
return cmp(x.lower(), y.lower())
def __init__(self, window, db):
QDialog.__init__(self, window)
Ui_TagListEditor.__init__(self)
self.setupUi(self)
self.to_delete = []
self.db = db
all_tags = [tag for tag in self.db.all_tags()]
all_tags = list(set(all_tags))
all_tags.sort(cmp=self.tag_cmp)
for tag in all_tags:
self.available_tags.addItem(tag)
self.connect(self.delete_button, SIGNAL('clicked()'), self.delete_tags)
def delete_tags(self, item=None):
confirms, deletes = [], []
items = self.available_tags.selectedItems() if item is None else [item]
if not items:
error_dialog(self, 'No tags selected', 'You must select at least one tag from the list of Available tags.').exec_()
return
for item in items:
if self.db.is_tag_used(unicode(item.text())):
confirms.append(item)
else:
deletes.append(item)
if confirms:
ct = ', '.join([unicode(item.text()) for item in confirms])
if question_dialog(self, _('Are your sure?'),
'<p>'+_('The following tags are used by one or more books. '
'Are you certain you want to delete them?')+'<br>'+ct):
deletes += confirms
for item in deletes:
self.to_delete.append(item)
self.available_tags.takeItem(self.available_tags.row(item))
def accept(self):
for item in self.to_delete:
self.db.delete_tag(unicode(item.text()))
QDialog.accept(self)

View File

@ -0,0 +1,132 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>TagListEditor</class>
<widget class="QDialog" name="TagListEditor">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>397</width>
<height>335</height>
</rect>
</property>
<property name="windowTitle">
<string>Tag Editor</string>
</property>
<property name="windowIcon">
<iconset>
<normaloff>:/images/chapters.svg</normaloff>:/images/chapters.svg</iconset>
</property>
<layout class="QGridLayout">
<item row="0" column="0">
<layout class="QVBoxLayout">
<item>
<layout class="QHBoxLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Tags in use</string>
</property>
<property name="buddy">
<cstring>available_tags</cstring>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout">
<item>
<widget class="QToolButton" name="delete_button">
<property name="toolTip">
<string>Delete tag from database. This will unapply the tag from all books and then remove it from the database.</string>
</property>
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset>
<normaloff>:/images/trash.svg</normaloff>:/images/trash.svg</iconset>
</property>
</widget>
</item>
<item>
<widget class="QListWidget" name="available_tags">
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::MultiSelection</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item row="1" column="0" colspan="2">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources>
<include location="../../../../resources/images.qrc"/>
</resources>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>TagListEditor</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>TagListEditor</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -8,10 +8,11 @@ Browsing book collection by tags.
'''
from itertools import izip
from functools import partial
from PyQt4.Qt import Qt, QTreeView, QApplication, pyqtSignal, \
QFont, QSize, QIcon, QPoint, \
QAbstractItemModel, QVariant, QModelIndex
QAbstractItemModel, QVariant, QModelIndex, QMenu
from calibre.gui2 import config, NONE
from calibre.utils.config import prefs
from calibre.library.field_metadata import TagsIcons
@ -22,6 +23,9 @@ class TagsView(QTreeView): # {{{
need_refresh = pyqtSignal()
restriction_set = pyqtSignal(object)
tags_marked = pyqtSignal(object, object)
user_category_edit = pyqtSignal(object)
tag_list_edit = pyqtSignal()
saved_search_edit = pyqtSignal(object)
def __init__(self, *args):
QTreeView.__init__(self, *args)
@ -31,13 +35,16 @@ class TagsView(QTreeView): # {{{
self.tag_match = None
def set_database(self, db, tag_match, popularity, restriction):
self._model = TagsModel(db, parent=self)
self.hidden_categories = config['tag_browser_hidden_categories']
self._model = TagsModel(db, parent=self, hidden_columns=self.hidden_categories)
self.popularity = popularity
self.restriction = restriction
self.tag_match = tag_match
self.db = db
self.setModel(self._model)
self.setContextMenuPolicy(Qt.CustomContextMenu)
self.clicked.connect(self.toggle)
self.customContextMenuRequested.connect(self.show_context_menu)
self.popularity.setChecked(config['sort_by_popularity'])
self.popularity.stateChanged.connect(self.sort_changed)
self.restriction.activated[str].connect(self.search_restriction_set)
@ -45,10 +52,6 @@ class TagsView(QTreeView): # {{{
db.add_listener(self.database_changed)
self.saved_searches_changed(recount=False)
def create_tag_category(self, name, tag_list):
self._model.create_tag_category(name, tag_list)
self.recount()
def database_changed(self, event, ids):
self.need_refresh.emit()
@ -72,12 +75,91 @@ class TagsView(QTreeView): # {{{
self.recount() # Must happen after the emission of the restriction_set signal
self.tags_marked.emit(self._model.tokens(), self.match_all)
def mouseReleaseEvent(self, event):
# Swallow everything except leftButton so context menus work correctly
if event.button() == Qt.LeftButton:
QTreeView.mouseReleaseEvent(self, event)
def toggle(self, index):
modifiers = int(QApplication.keyboardModifiers())
exclusive = modifiers not in (Qt.CTRL, Qt.SHIFT)
if self._model.toggle(index, exclusive):
self.tags_marked.emit(self._model.tokens(), self.match_all)
def context_menu_handler(self, action=None, category=None):
if not action:
return
try:
if action == 'manage_tags':
self.tag_list_edit.emit();
return
if action == 'manage_categories':
self.user_category_edit.emit(category)
return
if action == 'manage_searches':
self.saved_search_edit.emit(category)
return
if action == 'hide':
self.hidden_categories.add(category)
elif action == 'show':
self.hidden_categories.discard(category)
elif action == 'defaults':
self.hidden_categories.clear()
config.set('tag_browser_hidden_categories', self.hidden_categories)
self.set_new_model()
except:
return
def show_context_menu(self, point):
index = self.indexAt(point)
if not index.isValid():
return False
item = index.internalPointer()
tag_name = ''
if item.type == TagTreeItem.TAG:
tag_name = item.tag.name
item = item.parent
if item.type == TagTreeItem.CATEGORY:
category = unicode(item.name.toString())
self.context_menu = QMenu(self)
self.context_menu.addAction(_('Hide column %s') % category,
partial(self.context_menu_handler, action='hide', category=category))
if self.hidden_categories:
self.context_menu.addSeparator()
m = self.context_menu.addMenu(_('Show column'))
for col in self.hidden_categories:
m.addAction(col,
partial(self.context_menu_handler, action='show', category=col))
self.context_menu.addSeparator()
self.context_menu.addAction(_('Restore defaults'),
partial(self.context_menu_handler, action='defaults'))
self.context_menu.addSeparator()
self.context_menu.addAction(_('Manage Tags'),
partial(self.context_menu_handler, action='manage_tags'))
if category in prefs['user_categories'].keys():
self.context_menu.addAction(_('Manage User Categories'),
partial(self.context_menu_handler, action='manage_categories',
category=category))
else:
self.context_menu.addAction(_('Manage User Categories'),
partial(self.context_menu_handler, action='manage_categories',
category=None))
if tag_name in saved_searches.names():
self.context_menu.addAction(_('Manage Saved Searches'),
partial(self.context_menu_handler, action='manage_searches',
category=tag_name))
else:
self.context_menu.addAction(_('Manage Saved Searches'),
partial(self.context_menu_handler, action='manage_searches',
category=None))
self.context_menu.popup(self.mapToGlobal(point))
return True;
def clear(self):
self.model().clear_state()
@ -110,13 +192,12 @@ class TagsView(QTreeView): # {{{
self.setCurrentIndex(idx)
self.scrollTo(idx, QTreeView.PositionAtCenter)
'''
If the number of user categories changed, or if custom columns have come or gone,
we must rebuild the model. Reason: it is much easier to do that than to reconstruct
the browser tree.
'''
# If the number of user categories changed, if custom columns have come or
# gone, or if columns have been hidden or restored, we must rebuild the
# model. Reason: it is much easier than reconstructing the browser tree.
def set_new_model(self):
self._model = TagsModel(self.db, parent=self)
self._model = TagsModel(self.db, parent=self,
hidden_categories=self.hidden_categories)
self.setModel(self._model)
# }}}
@ -200,7 +281,7 @@ class TagTreeItem(object): # {{{
class TagsModel(QAbstractItemModel): # {{{
def __init__(self, db, parent=None):
def __init__(self, db, parent=None, hidden_categories=None):
QAbstractItemModel.__init__(self, parent)
# must do this here because 'QPixmap: Must construct a QApplication
@ -220,6 +301,7 @@ class TagsModel(QAbstractItemModel): # {{{
self.icon_state_map = [None, QIcon(I('plus.svg')), QIcon(I('minus.svg'))]
self.db = db
self.hidden_categories = hidden_categories
self.search_restriction = ''
self.ignore_next_search = 0
@ -237,6 +319,8 @@ class TagsModel(QAbstractItemModel): # {{{
data = self.get_node_tree(config['sort_by_popularity'])
self.root_item = TagTreeItem()
for i, r in enumerate(self.row_map):
if self.categories[i]in self.hidden_categories:
continue
if self.db.field_metadata[r]['kind'] != 'user':
tt = _('The lookup/search name is "{0}"').format(r)
else:
@ -271,12 +355,16 @@ class TagsModel(QAbstractItemModel): # {{{
def refresh(self):
data = self.get_node_tree(config['sort_by_popularity']) # get category data
row_index = -1;
for i, r in enumerate(self.row_map):
category = self.root_item.children[i]
if self.categories[i] in self.hidden_categories:
continue
row_index += 1
category = self.root_item.children[row_index]
names = [t.tag.name for t in category.children]
states = [t.tag.state for t in category.children]
state_map = dict(izip(names, states))
category_index = self.index(i, 0, QModelIndex())
category_index = self.index(row_index, 0, QModelIndex())
if len(category.children) > 0:
self.beginRemoveRows(category_index, 0,
len(category.children)-1)
@ -401,10 +489,14 @@ class TagsModel(QAbstractItemModel): # {{{
def tokens(self):
ans = []
tags_seen = set()
row_index = -1;
for i, key in enumerate(self.row_map):
if self.categories[i] in self.hidden_categories:
continue
row_index += 1
if key.endswith(':'): # User category, so skip it. The tag will be marked in its real category
continue
category_item = self.root_item.children[i]
category_item = self.root_item.children[row_index]
for tag_item in category_item.children:
tag = tag_item.tag
if tag.state > 0:

View File

@ -61,6 +61,8 @@ from calibre.library.database2 import LibraryDatabase2
from calibre.library.caches import CoverCache
from calibre.gui2.dialogs.confirm_delete import confirm
from calibre.gui2.dialogs.tag_categories import TagCategories
from calibre.gui2.dialogs.tag_list_editor import TagListEditor
from calibre.gui2.dialogs.saved_search_editor import SavedSearchEditor
class SaveMenu(QMenu):
@ -537,19 +539,23 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
self.cover_cache = CoverCache(self.library_path)
self.cover_cache.start()
self.library_view.model().cover_cache = self.cover_cache
self.connect(self.edit_categories, SIGNAL('clicked()'), self.do_edit_categories)
self.connect(self.edit_categories, SIGNAL('clicked()'), self.do_user_categories_edit)
self.tags_view.set_database(db, self.tag_match, self.popularity, self.search_restriction)
self.tags_view.tags_marked.connect(self.search.search_from_tags)
for x in (self.saved_search.clear_to_help, self.mark_restriction_set):
self.tags_view.restriction_set.connect(x)
self.tags_view.tags_marked.connect(self.saved_search.clear_to_help)
self.tags_view.tag_list_edit.connect(self.do_tags_list_edit)
self.tags_view.user_category_edit.connect(self.do_user_categories_edit)
self.tags_view.saved_search_edit.connect(self.do_saved_search_edit)
self.search.search.connect(self.tags_view.model().reinit)
for x in (self.location_view.count_changed, self.tags_view.recount,
self.restriction_count_changed):
self.library_view.model().count_changed_signal.connect(x)
self.connect(self.search, SIGNAL('cleared()'), self.search_box_cleared)
self.connect(self.saved_search, SIGNAL('changed()'), self.tags_view.saved_searches_changed, Qt.QueuedConnection)
self.connect(self.saved_search, SIGNAL('changed()'),
self.tags_view.saved_searches_changed, Qt.QueuedConnection)
if not gprefs.get('quick_start_guide_added', False):
from calibre.ebooks.metadata import MetaInformation
mi = MetaInformation(_('Calibre Quick Start Guide'), ['John Schember'])
@ -642,13 +648,28 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
self._add_filesystem_book = Dispatcher(self.__add_filesystem_book)
self.keyboard_interrupt.connect(self.quit, type=Qt.QueuedConnection)
def do_edit_categories(self):
d = TagCategories(self, self.library_view.model().db)
def do_user_categories_edit(self, on_category=None):
d = TagCategories(self, self.library_view.model().db, on_category)
d.exec_()
if d.result() == d.Accepted:
self.tags_view.set_new_model()
self.tags_view.recount()
def do_tags_list_edit(self):
d = TagListEditor(self, self.library_view.model().db)
d.exec_()
if d.result() == d.Accepted:
self.tags_view.set_new_model()
self.tags_view.recount()
self.library_view.model().refresh()
def do_saved_search_edit(self, search):
d = SavedSearchEditor(self, search)
d.exec_()
if d.result() == d.Accepted:
self.tags_view.saved_searches_changed(recount=True)
self.saved_search.clear_to_help()
def resizeEvent(self, ev):
MainWindow.resizeEvent(self, ev)
self.search.setMaximumWidth(self.width()-150)