Jobs list: Implement searching

This commit is contained in:
Kovid Goyal 2011-11-15 12:45:50 +05:30
parent efd0209ce6
commit cafc97cca7
3 changed files with 120 additions and 18 deletions

View File

@ -175,6 +175,8 @@ def _config(): # {{{
help='Search history for the plugin preferences')
c.add_opt('shortcuts_search_history', default=[],
help='Search history for the keyboard preferences')
c.add_opt('jobs_search_history', default=[],
help='Search history for the keyboard preferences')
c.add_opt('tweaks_search_history', default=[],
help='Search history for tweaks')
c.add_opt('worker_limit', default=6,

View File

@ -19,6 +19,34 @@
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0" colspan="2">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="SearchBox2" name="search"/>
</item>
<item>
<widget class="QToolButton" name="search_button">
<property name="toolTip">
<string>Find next match</string>
</property>
<property name="text">
<string>&amp;Search</string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="clear_button">
<property name="toolTip">
<string>Find previous match</string>
</property>
<property name="icon">
<iconset resource="../../../../resources/images.qrc">
<normaloff>:/images/clear_left.png</normaloff>:/images/clear_left.png</iconset>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="0" colspan="2">
<widget class="QTableView" name="jobs_view">
<property name="contextMenuPolicy">
<enum>Qt::NoContextMenu</enum>
@ -40,42 +68,42 @@
</property>
</widget>
</item>
<item row="1" column="0">
<item row="2" column="0">
<widget class="QPushButton" name="kill_button">
<property name="text">
<string>&amp;Stop selected jobs</string>
</property>
</widget>
</item>
<item row="1" column="1">
<item row="2" column="1">
<widget class="QPushButton" name="hide_button">
<property name="text">
<string>&amp;Hide selected jobs</string>
</property>
</widget>
</item>
<item row="2" column="0">
<item row="3" column="0">
<widget class="QPushButton" name="details_button">
<property name="text">
<string>Show job &amp;details</string>
</property>
</widget>
</item>
<item row="2" column="1">
<item row="3" column="1">
<widget class="QPushButton" name="show_button">
<property name="text">
<string>Show &amp;all jobs</string>
</property>
</widget>
</item>
<item row="3" column="0">
<item row="4" column="0">
<widget class="QPushButton" name="stop_all_jobs_button">
<property name="text">
<string>Stop &amp;all non device jobs</string>
</property>
</widget>
</item>
<item row="3" column="1">
<item row="4" column="1">
<widget class="QPushButton" name="hide_all_button">
<property name="text">
<string>&amp;Hide all jobs</string>
@ -84,6 +112,13 @@
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>SearchBox2</class>
<extends>QComboBox</extends>
<header>calibre/gui2/search_box.h</header>
</customwidget>
</customwidgets>
<resources>
<include location="../../../../resources/images.qrc"/>
</resources>

View File

@ -18,23 +18,26 @@ from PyQt4.Qt import (QAbstractTableModel, QVariant, QModelIndex, Qt,
from calibre.utils.ipc.server import Server
from calibre.utils.ipc.job import ParallelJob
from calibre.gui2 import Dispatcher, error_dialog, question_dialog, NONE, config, gprefs
from calibre.gui2 import (Dispatcher, error_dialog, question_dialog, NONE,
config, gprefs)
from calibre.gui2.device import DeviceJob
from calibre.gui2.dialogs.jobs_ui import Ui_JobsDialog
from calibre import __appname__, as_unicode
from calibre.gui2.dialogs.job_view_ui import Ui_Dialog
from calibre.gui2.progress_indicator import ProgressIndicator
from calibre.gui2.threaded_jobs import ThreadedJobServer, ThreadedJob
from calibre.utils.search_query_parser import SearchQueryParser, ParseException
from calibre.utils.icu import lower
HIDE_ROLE = Qt.UserRole + 1
class JobManager(QAbstractTableModel): # {{{
class JobManager(QAbstractTableModel, SearchQueryParser): # {{{
job_added = pyqtSignal(int)
job_done = pyqtSignal(int)
def __init__(self):
QAbstractTableModel.__init__(self)
SearchQueryParser.__init__(self, ['all'])
self.wait_icon = QVariant(QIcon(I('jobs.png')))
self.running_icon = QVariant(QIcon(I('exec.png')))
self.error_icon = QVariant(QIcon(I('dialog_error.png')))
@ -93,7 +96,7 @@ class JobManager(QAbstractTableModel): # {{{
def data(self, index, role):
try:
if role not in (Qt.DisplayRole, Qt.DecorationRole, HIDE_ROLE):
if role not in (Qt.DisplayRole, Qt.DecorationRole):
return NONE
row, col = index.row(), index.column()
job = self.jobs[row]
@ -123,9 +126,6 @@ class JobManager(QAbstractTableModel): # {{{
if job.killed or job.failed:
return self.error_icon
return self.done_icon
if role == HIDE_ROLE:
return QVariant('h' if getattr(job, 'hidden_in_gui', False)
else 's')
except:
import traceback
traceback.print_exc()
@ -316,6 +316,62 @@ class JobManager(QAbstractTableModel): # {{{
continue
if not isinstance(job, ParallelJob):
self._kill_job(job)
def universal_set(self):
return set([i for i, j in enumerate(self.jobs) if not getattr(j,
'hidden_in_gui', False)])
def get_matches(self, location, query, candidates=None):
if candidates is None:
candidates = self.universal_set()
ans = set()
if not query:
return ans
query = lower(query)
for j in candidates:
job = self.jobs[j]
if job.description and query in lower(job.description):
ans.add(j)
return ans
def find(self, query):
query = query.strip()
rows = self.parse(query)
return rows
# }}}
class FilterModel(QSortFilterProxyModel): # {{{
search_done = pyqtSignal(object)
def __init__(self, parent):
QSortFilterProxyModel.__init__(self, parent)
self.search_filter = None
def filterAcceptsRow(self, source_row, source_parent):
if (self.search_filter is not None and source_row not in
self.search_filter):
return False
m = self.sourceModel()
try:
job = m.row_to_job(source_row)
except:
return False
return not getattr(job, 'hidden_in_gui', False)
def find(self, query):
ok = True
val = None
if query:
try:
val = self.sourceModel().parse(query)
except ParseException:
ok = False
self.search_filter = val
self.search_done.emit(ok)
self.reset()
# }}}
# Jobs UI {{{
@ -468,10 +524,9 @@ class JobsDialog(QDialog, Ui_JobsDialog):
Ui_JobsDialog.__init__(self)
self.setupUi(self)
self.model = model
self.proxy_model = QSortFilterProxyModel(self)
self.proxy_model = FilterModel(self)
self.proxy_model.setSourceModel(self.model)
self.proxy_model.setFilterRole(HIDE_ROLE)
self.proxy_model.setFilterFixedString('s')
self.proxy_model.search_done.connect(self.search.search_done)
self.jobs_view.setModel(self.proxy_model)
self.setWindowModality(Qt.NonModal)
self.setWindowTitle(__appname__ + _(' - Jobs'))
@ -485,6 +540,12 @@ class JobsDialog(QDialog, Ui_JobsDialog):
self.hide_button.clicked.connect(self.hide_selected)
self.hide_all_button.clicked.connect(self.hide_all)
self.show_button.clicked.connect(self.show_hidden)
self.search.initialize('jobs_search_history',
help_text=_('Search for a job by name'))
self.search.search.connect(self.find)
self.search_button.clicked.connect(lambda :
self.find(self.search.current_text))
self.clear_button.clicked.connect(lambda : self.search.clear())
self.restore_state()
def restore_state(self):
@ -563,7 +624,7 @@ class JobsDialog(QDialog, Ui_JobsDialog):
def show_hidden(self, *args):
self.model.show_hidden_jobs()
self.proxy_model.reset()
self.find(self.search.current_text)
def closeEvent(self, e):
self.save_state()
@ -576,5 +637,9 @@ class JobsDialog(QDialog, Ui_JobsDialog):
def hide(self, *args):
self.save_state()
return QDialog.hide(self, *args)
def find(self, query):
self.proxy_model.find(query)
# }}}