mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-06-23 15:30:45 -04:00
Jobs list: Implement searching
This commit is contained in:
parent
efd0209ce6
commit
cafc97cca7
@ -175,6 +175,8 @@ def _config(): # {{{
|
|||||||
help='Search history for the plugin preferences')
|
help='Search history for the plugin preferences')
|
||||||
c.add_opt('shortcuts_search_history', default=[],
|
c.add_opt('shortcuts_search_history', default=[],
|
||||||
help='Search history for the keyboard preferences')
|
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=[],
|
c.add_opt('tweaks_search_history', default=[],
|
||||||
help='Search history for tweaks')
|
help='Search history for tweaks')
|
||||||
c.add_opt('worker_limit', default=6,
|
c.add_opt('worker_limit', default=6,
|
||||||
|
@ -19,6 +19,34 @@
|
|||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout">
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
<item row="0" column="0" colspan="2">
|
<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>&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">
|
<widget class="QTableView" name="jobs_view">
|
||||||
<property name="contextMenuPolicy">
|
<property name="contextMenuPolicy">
|
||||||
<enum>Qt::NoContextMenu</enum>
|
<enum>Qt::NoContextMenu</enum>
|
||||||
@ -40,42 +68,42 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="0">
|
<item row="2" column="0">
|
||||||
<widget class="QPushButton" name="kill_button">
|
<widget class="QPushButton" name="kill_button">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>&Stop selected jobs</string>
|
<string>&Stop selected jobs</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="1">
|
<item row="2" column="1">
|
||||||
<widget class="QPushButton" name="hide_button">
|
<widget class="QPushButton" name="hide_button">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>&Hide selected jobs</string>
|
<string>&Hide selected jobs</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="0">
|
<item row="3" column="0">
|
||||||
<widget class="QPushButton" name="details_button">
|
<widget class="QPushButton" name="details_button">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Show job &details</string>
|
<string>Show job &details</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="1">
|
<item row="3" column="1">
|
||||||
<widget class="QPushButton" name="show_button">
|
<widget class="QPushButton" name="show_button">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Show &all jobs</string>
|
<string>Show &all jobs</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="3" column="0">
|
<item row="4" column="0">
|
||||||
<widget class="QPushButton" name="stop_all_jobs_button">
|
<widget class="QPushButton" name="stop_all_jobs_button">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Stop &all non device jobs</string>
|
<string>Stop &all non device jobs</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="3" column="1">
|
<item row="4" column="1">
|
||||||
<widget class="QPushButton" name="hide_all_button">
|
<widget class="QPushButton" name="hide_all_button">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>&Hide all jobs</string>
|
<string>&Hide all jobs</string>
|
||||||
@ -84,6 +112,13 @@
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
|
<customwidgets>
|
||||||
|
<customwidget>
|
||||||
|
<class>SearchBox2</class>
|
||||||
|
<extends>QComboBox</extends>
|
||||||
|
<header>calibre/gui2/search_box.h</header>
|
||||||
|
</customwidget>
|
||||||
|
</customwidgets>
|
||||||
<resources>
|
<resources>
|
||||||
<include location="../../../../resources/images.qrc"/>
|
<include location="../../../../resources/images.qrc"/>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -18,23 +18,26 @@ from PyQt4.Qt import (QAbstractTableModel, QVariant, QModelIndex, Qt,
|
|||||||
|
|
||||||
from calibre.utils.ipc.server import Server
|
from calibre.utils.ipc.server import Server
|
||||||
from calibre.utils.ipc.job import ParallelJob
|
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.device import DeviceJob
|
||||||
from calibre.gui2.dialogs.jobs_ui import Ui_JobsDialog
|
from calibre.gui2.dialogs.jobs_ui import Ui_JobsDialog
|
||||||
from calibre import __appname__, as_unicode
|
from calibre import __appname__, as_unicode
|
||||||
from calibre.gui2.dialogs.job_view_ui import Ui_Dialog
|
from calibre.gui2.dialogs.job_view_ui import Ui_Dialog
|
||||||
from calibre.gui2.progress_indicator import ProgressIndicator
|
from calibre.gui2.progress_indicator import ProgressIndicator
|
||||||
from calibre.gui2.threaded_jobs import ThreadedJobServer, ThreadedJob
|
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, SearchQueryParser): # {{{
|
||||||
|
|
||||||
class JobManager(QAbstractTableModel): # {{{
|
|
||||||
|
|
||||||
job_added = pyqtSignal(int)
|
job_added = pyqtSignal(int)
|
||||||
job_done = pyqtSignal(int)
|
job_done = pyqtSignal(int)
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
QAbstractTableModel.__init__(self)
|
QAbstractTableModel.__init__(self)
|
||||||
|
SearchQueryParser.__init__(self, ['all'])
|
||||||
|
|
||||||
self.wait_icon = QVariant(QIcon(I('jobs.png')))
|
self.wait_icon = QVariant(QIcon(I('jobs.png')))
|
||||||
self.running_icon = QVariant(QIcon(I('exec.png')))
|
self.running_icon = QVariant(QIcon(I('exec.png')))
|
||||||
self.error_icon = QVariant(QIcon(I('dialog_error.png')))
|
self.error_icon = QVariant(QIcon(I('dialog_error.png')))
|
||||||
@ -93,7 +96,7 @@ class JobManager(QAbstractTableModel): # {{{
|
|||||||
|
|
||||||
def data(self, index, role):
|
def data(self, index, role):
|
||||||
try:
|
try:
|
||||||
if role not in (Qt.DisplayRole, Qt.DecorationRole, HIDE_ROLE):
|
if role not in (Qt.DisplayRole, Qt.DecorationRole):
|
||||||
return NONE
|
return NONE
|
||||||
row, col = index.row(), index.column()
|
row, col = index.row(), index.column()
|
||||||
job = self.jobs[row]
|
job = self.jobs[row]
|
||||||
@ -123,9 +126,6 @@ class JobManager(QAbstractTableModel): # {{{
|
|||||||
if job.killed or job.failed:
|
if job.killed or job.failed:
|
||||||
return self.error_icon
|
return self.error_icon
|
||||||
return self.done_icon
|
return self.done_icon
|
||||||
if role == HIDE_ROLE:
|
|
||||||
return QVariant('h' if getattr(job, 'hidden_in_gui', False)
|
|
||||||
else 's')
|
|
||||||
except:
|
except:
|
||||||
import traceback
|
import traceback
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
@ -316,6 +316,62 @@ class JobManager(QAbstractTableModel): # {{{
|
|||||||
continue
|
continue
|
||||||
if not isinstance(job, ParallelJob):
|
if not isinstance(job, ParallelJob):
|
||||||
self._kill_job(job)
|
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 {{{
|
# Jobs UI {{{
|
||||||
@ -468,10 +524,9 @@ class JobsDialog(QDialog, Ui_JobsDialog):
|
|||||||
Ui_JobsDialog.__init__(self)
|
Ui_JobsDialog.__init__(self)
|
||||||
self.setupUi(self)
|
self.setupUi(self)
|
||||||
self.model = model
|
self.model = model
|
||||||
self.proxy_model = QSortFilterProxyModel(self)
|
self.proxy_model = FilterModel(self)
|
||||||
self.proxy_model.setSourceModel(self.model)
|
self.proxy_model.setSourceModel(self.model)
|
||||||
self.proxy_model.setFilterRole(HIDE_ROLE)
|
self.proxy_model.search_done.connect(self.search.search_done)
|
||||||
self.proxy_model.setFilterFixedString('s')
|
|
||||||
self.jobs_view.setModel(self.proxy_model)
|
self.jobs_view.setModel(self.proxy_model)
|
||||||
self.setWindowModality(Qt.NonModal)
|
self.setWindowModality(Qt.NonModal)
|
||||||
self.setWindowTitle(__appname__ + _(' - Jobs'))
|
self.setWindowTitle(__appname__ + _(' - Jobs'))
|
||||||
@ -485,6 +540,12 @@ class JobsDialog(QDialog, Ui_JobsDialog):
|
|||||||
self.hide_button.clicked.connect(self.hide_selected)
|
self.hide_button.clicked.connect(self.hide_selected)
|
||||||
self.hide_all_button.clicked.connect(self.hide_all)
|
self.hide_all_button.clicked.connect(self.hide_all)
|
||||||
self.show_button.clicked.connect(self.show_hidden)
|
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()
|
self.restore_state()
|
||||||
|
|
||||||
def restore_state(self):
|
def restore_state(self):
|
||||||
@ -563,7 +624,7 @@ class JobsDialog(QDialog, Ui_JobsDialog):
|
|||||||
|
|
||||||
def show_hidden(self, *args):
|
def show_hidden(self, *args):
|
||||||
self.model.show_hidden_jobs()
|
self.model.show_hidden_jobs()
|
||||||
self.proxy_model.reset()
|
self.find(self.search.current_text)
|
||||||
|
|
||||||
def closeEvent(self, e):
|
def closeEvent(self, e):
|
||||||
self.save_state()
|
self.save_state()
|
||||||
@ -576,5 +637,9 @@ class JobsDialog(QDialog, Ui_JobsDialog):
|
|||||||
def hide(self, *args):
|
def hide(self, *args):
|
||||||
self.save_state()
|
self.save_state()
|
||||||
return QDialog.hide(self, *args)
|
return QDialog.hide(self, *args)
|
||||||
|
|
||||||
|
def find(self, query):
|
||||||
|
self.proxy_model.find(query)
|
||||||
|
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user