mirror of
https://github.com/olivierkes/manuskript.git
synced 2024-05-18 20:02:32 +12:00
Adds: search widget
This commit is contained in:
parent
719f6e6fe0
commit
9404a4b92e
|
@ -59,9 +59,10 @@ class outlineModel(QAbstractItemModel):
|
|||
"Returns a list of IDs of all items whose POV is ``POV``."
|
||||
return self.rootItem.findItemsByPOV(POV)
|
||||
|
||||
def findItemsContaining(self, text, column):
|
||||
"Returns a list of IDs of all items containing ``text`` in column ``column``."
|
||||
return self.rootItem.findItemsContaining(text, column)
|
||||
def findItemsContaining(self, text, columns, caseSensitive=False):
|
||||
"""Returns a list of IDs of all items containing ``text``
|
||||
in columns ``columns`` (being a list of int)."""
|
||||
return self.rootItem.findItemsContaining(text, columns, mainWindow(), caseSensitive)
|
||||
|
||||
def getIndexByID(self, ID):
|
||||
"Returns the index of item whose ID is ``ID``. If none, returns QModelIndex()."
|
||||
|
@ -764,15 +765,34 @@ class outlineItem():
|
|||
|
||||
return lst
|
||||
|
||||
def findItemsContaining(self, text, column):
|
||||
def findItemsContaining(self, text, columns, mainWindow, caseSensitive=False):
|
||||
"""Returns a list if IDs of all subitems
|
||||
containing ``text`` in column ``column``.
|
||||
containing ``text`` in columns ``columns``
|
||||
(being a list of int).
|
||||
"""
|
||||
lst = []
|
||||
if text in self.data(column):
|
||||
lst.append(self.ID())
|
||||
text = text.lower() if not caseSensitive else text
|
||||
for c in columns:
|
||||
|
||||
if c == Outline.POV.value:
|
||||
searchIn = mainWindow.mdlPersos.getPersoNameByID(self.POV())
|
||||
|
||||
elif c == Outline.status.value:
|
||||
searchIn = mainWindow.mdlStatus.item(toInt(self.status()), 0).text()
|
||||
|
||||
elif c == Outline.label.value:
|
||||
searchIn = mainWindow.mdlLabels.item(toInt(self.label()), 0).text()
|
||||
|
||||
else:
|
||||
searchIn = self.data(c)
|
||||
|
||||
searchIn = searchIn.lower() if not caseSensitive else searchIn
|
||||
|
||||
if text in searchIn:
|
||||
if not self.ID() in lst:
|
||||
lst.append(self.ID())
|
||||
|
||||
for c in self.children():
|
||||
lst.extend(c.findItemsContaining(text, column))
|
||||
lst.extend(c.findItemsContaining(text, columns, mainWindow, caseSensitive))
|
||||
|
||||
return lst
|
|
@ -46,7 +46,7 @@ class persosModel(QStandardItemModel):
|
|||
index = self.getIndexFromID(ID)
|
||||
if index.isValid():
|
||||
return self.name(index.row())
|
||||
return None
|
||||
return ""
|
||||
|
||||
def getIndexFromID(self, ID):
|
||||
for i in range(self.rowCount()):
|
||||
|
|
|
@ -149,7 +149,7 @@ def infoForRef(ref):
|
|||
|
||||
# List scences where character is referenced
|
||||
listRefs = ""
|
||||
lst = oM.findItemsContaining(ref, Outline.notes.value)
|
||||
lst = oM.findItemsContaining(ref, [Outline.notes.value])
|
||||
for t in lst:
|
||||
idx = oM.getIndexByID(t)
|
||||
listRefs += "<li><a href='{link}'>{text}</a>".format(
|
||||
|
|
|
@ -15,7 +15,7 @@ class cheatSheet(QWidget, Ui_cheatSheet):
|
|||
def __init__(self, parent=None):
|
||||
QWidget.__init__(self, parent)
|
||||
self.setupUi(self)
|
||||
self.splitter.setStretchFactor(0, 3)
|
||||
self.splitter.setStretchFactor(0, 5)
|
||||
self.splitter.setStretchFactor(1, 70)
|
||||
|
||||
self.txtFilter.textChanged.connect(self.updateListFromData)
|
||||
|
|
|
@ -844,7 +844,6 @@ class Ui_MainWindow(object):
|
|||
self.groupBox_3.setFlat(True)
|
||||
self.groupBox_3.setObjectName("groupBox_3")
|
||||
self.verticalLayout_15 = QtWidgets.QVBoxLayout(self.groupBox_3)
|
||||
self.verticalLayout_15.setContentsMargins(0, 0, 0, 0)
|
||||
self.verticalLayout_15.setObjectName("verticalLayout_15")
|
||||
self.cheatSheet = cheatSheet(self.groupBox_3)
|
||||
font = QtGui.QFont()
|
||||
|
@ -854,6 +853,23 @@ class Ui_MainWindow(object):
|
|||
self.cheatSheet.setObjectName("cheatSheet")
|
||||
self.verticalLayout_15.addWidget(self.cheatSheet)
|
||||
self.verticalLayout_21.addWidget(self.groupBox_3)
|
||||
self.groupBox_4 = collapsibleGroupBox2(self.tab_18)
|
||||
font = QtGui.QFont()
|
||||
font.setBold(True)
|
||||
font.setWeight(75)
|
||||
self.groupBox_4.setFont(font)
|
||||
self.groupBox_4.setFlat(True)
|
||||
self.groupBox_4.setObjectName("groupBox_4")
|
||||
self.verticalLayout_31 = QtWidgets.QVBoxLayout(self.groupBox_4)
|
||||
self.verticalLayout_31.setObjectName("verticalLayout_31")
|
||||
self.widget = search(self.groupBox_4)
|
||||
font = QtGui.QFont()
|
||||
font.setBold(False)
|
||||
font.setWeight(50)
|
||||
self.widget.setFont(font)
|
||||
self.widget.setObjectName("widget")
|
||||
self.verticalLayout_31.addWidget(self.widget)
|
||||
self.verticalLayout_21.addWidget(self.groupBox_4)
|
||||
self.tabRedacInfos.addTab(self.tab_18, "")
|
||||
self.verticalLayout_16.addWidget(self.splitterRedac)
|
||||
self.tabMain.addTab(self.lytTabRedac, "")
|
||||
|
@ -1029,7 +1045,7 @@ class Ui_MainWindow(object):
|
|||
self.stack.setCurrentIndex(1)
|
||||
self.tabMain.setCurrentIndex(6)
|
||||
self.tabSummary.setCurrentIndex(0)
|
||||
self.tabPersos.setCurrentIndex(3)
|
||||
self.tabPersos.setCurrentIndex(0)
|
||||
self.tabPlot.setCurrentIndex(0)
|
||||
self.comboBox_2.setCurrentIndex(0)
|
||||
self.stkPlotSummary.setCurrentIndex(0)
|
||||
|
@ -1113,6 +1129,7 @@ class Ui_MainWindow(object):
|
|||
self.tabMain.setTabText(self.tabMain.indexOf(self.lytTabOutline), _translate("MainWindow", "Outline"))
|
||||
self.tabRedacInfos.setTabText(self.tabRedacInfos.indexOf(self.tab_17), _translate("MainWindow", "Metadata"))
|
||||
self.groupBox_3.setTitle(_translate("MainWindow", "Cheat sheet"))
|
||||
self.groupBox_4.setTitle(_translate("MainWindow", "Search"))
|
||||
self.tabRedacInfos.setTabText(self.tabRedacInfos.indexOf(self.tab_18), _translate("MainWindow", "Tools"))
|
||||
self.tabMain.setTabText(self.tabMain.indexOf(self.lytTabRedac), _translate("MainWindow", "Redaction"))
|
||||
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_9), _translate("MainWindow", "FlatData"))
|
||||
|
@ -1152,16 +1169,17 @@ class Ui_MainWindow(object):
|
|||
self.actSettings.setShortcut(_translate("MainWindow", "F8"))
|
||||
self.actCloseProject.setText(_translate("MainWindow", "Close project"))
|
||||
|
||||
from ui.views.treeView import treeView
|
||||
from ui.editors.mainEditor import mainEditor
|
||||
from ui.views.persoTreeView import persoTreeView
|
||||
from ui.sldImportance import sldImportance
|
||||
from ui.cheatSheet import cheatSheet
|
||||
from ui.views.basicItemView import basicItemView
|
||||
from ui.views.metadataView import metadataView
|
||||
from ui.search import search
|
||||
from ui.views.outlineView import outlineView
|
||||
from ui.collapsibleGroupBox2 import collapsibleGroupBox2
|
||||
from ui.views.metadataView import metadataView
|
||||
from ui.views.lineEditView import lineEditView
|
||||
from ui.views.persoTreeView import persoTreeView
|
||||
from ui.sldImportance import sldImportance
|
||||
from ui.views.basicItemView import basicItemView
|
||||
from ui.views.treeView import treeView
|
||||
from ui.cheatSheet import cheatSheet
|
||||
from ui.views.plotTreeView import plotTreeView
|
||||
from ui.views.textEditView import textEditView
|
||||
from ui.welcome import welcome
|
||||
from ui.views.textEditView import textEditView
|
||||
from ui.views.lineEditView import lineEditView
|
||||
|
|
|
@ -717,7 +717,7 @@
|
|||
</widget>
|
||||
<widget class="QTabWidget" name="tabPersos">
|
||||
<property name="currentIndex">
|
||||
<number>3</number>
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="infos">
|
||||
<attribute name="title">
|
||||
|
@ -1628,9 +1628,6 @@
|
|||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_15">
|
||||
<property name="margin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="cheatSheet" name="cheatSheet" native="true">
|
||||
<property name="font">
|
||||
|
@ -1644,6 +1641,34 @@
|
|||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="collapsibleGroupBox2" name="groupBox_4">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Search</string>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_31">
|
||||
<item>
|
||||
<widget class="search" name="widget" native="true">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>50</weight>
|
||||
<bold>false</bold>
|
||||
</font>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
|
@ -2045,6 +2070,12 @@
|
|||
<header>ui.collapsibleGroupBox2.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>search</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>ui.search.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections>
|
||||
|
@ -2055,8 +2086,8 @@
|
|||
<slot>setVisible(bool)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>325</x>
|
||||
<y>787</y>
|
||||
<x>342</x>
|
||||
<y>760</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>860</x>
|
||||
|
@ -2087,12 +2118,12 @@
|
|||
<slot>setVisible(bool)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>1088</x>
|
||||
<y>770</y>
|
||||
<x>1136</x>
|
||||
<y>768</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>1053</x>
|
||||
<y>731</y>
|
||||
<x>1137</x>
|
||||
<y>729</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
|
@ -2135,12 +2166,12 @@
|
|||
<slot>setVisible(bool)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>742</x>
|
||||
<y>762</y>
|
||||
<x>446</x>
|
||||
<y>127</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>742</x>
|
||||
<y>749</y>
|
||||
<x>446</x>
|
||||
<y>120</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
|
|
150
src/ui/search.py
Normal file
150
src/ui/search.py
Normal file
|
@ -0,0 +1,150 @@
|
|||
#!/usr/bin/env python
|
||||
#--!-- coding: utf8 --!--
|
||||
|
||||
from qt import *
|
||||
from enums import *
|
||||
from models.outlineModel import *
|
||||
from ui.search_ui import *
|
||||
from functions import *
|
||||
from models.references import *
|
||||
|
||||
class search(QWidget, Ui_search):
|
||||
|
||||
def __init__(self, parent=None):
|
||||
QWidget.__init__(self, parent)
|
||||
self.setupUi(self)
|
||||
|
||||
self.options = {
|
||||
"All": True,
|
||||
"Title": True,
|
||||
"Text": True,
|
||||
"Summary": False,
|
||||
"Notes": False,
|
||||
"POV": False,
|
||||
"Status": False,
|
||||
"Label": False,
|
||||
"CS": True
|
||||
}
|
||||
|
||||
self.text.returnPressed.connect(self.search)
|
||||
self.generateOptionMenu()
|
||||
|
||||
self.delegate = listResultDelegate(self)
|
||||
self.result.setItemDelegate(self.delegate)
|
||||
self.result.itemActivated.connect(self.openItem)
|
||||
|
||||
def generateOptionMenu(self):
|
||||
self.menu = QMenu(self)
|
||||
a = QAction(self.tr("Search in:"), self.menu)
|
||||
a.setEnabled(False)
|
||||
self.menu.addAction(a)
|
||||
for i, d in [
|
||||
(self.tr("All"), "All"),
|
||||
(self.tr("Title"), "Title"),
|
||||
(self.tr("Text"), "Text"),
|
||||
(self.tr("Summary"), "Summary"),
|
||||
(self.tr("Notes"), "Notes"),
|
||||
(self.tr("POV"), "POV"),
|
||||
(self.tr("Status"), "Status"),
|
||||
(self.tr("Label"), "Label"),
|
||||
]:
|
||||
a = QAction(i, self.menu)
|
||||
a.setCheckable(True)
|
||||
a.setChecked(self.options[d])
|
||||
a.setData(d)
|
||||
a.triggered.connect(self.updateOptions)
|
||||
self.menu.addAction(a)
|
||||
self.menu.addSeparator()
|
||||
|
||||
a = QAction(self.tr("Options:"), self.menu)
|
||||
a.setEnabled(False)
|
||||
self.menu.addAction(a)
|
||||
for i, d in [
|
||||
(self.tr("Case sensitive"), "CS"),
|
||||
]:
|
||||
a = QAction(i, self.menu)
|
||||
a.setCheckable(True)
|
||||
a.setChecked(self.options[d])
|
||||
a.setData(d)
|
||||
a.triggered.connect(self.updateOptions)
|
||||
self.menu.addAction(a)
|
||||
self.menu.addSeparator()
|
||||
|
||||
self.btnOptions.setMenu(self.menu)
|
||||
|
||||
def updateOptions(self):
|
||||
a = self.sender()
|
||||
self.options[a.data()] = a.isChecked()
|
||||
|
||||
def search(self):
|
||||
text = self.text.text()
|
||||
|
||||
# Chosing the right columns
|
||||
lstColumns = [
|
||||
("Title", Outline.title.value),
|
||||
("Text", Outline.text.value),
|
||||
("Summary", Outline.summarySentance.value),
|
||||
("Summary", Outline.summaryFull.value),
|
||||
("Notes", Outline.notes.value),
|
||||
("POV", Outline.POV.value),
|
||||
("Status", Outline.status.value),
|
||||
("Label", Outline.label.value),
|
||||
]
|
||||
columns = [c[1] for c in lstColumns if self.options[c[0]] or self.options["All"]]
|
||||
|
||||
# Setting override cursor
|
||||
qApp.setOverrideCursor(Qt.WaitCursor)
|
||||
|
||||
# Searching
|
||||
model = mainWindow().mdlOutline
|
||||
results = model.findItemsContaining(text, columns, self.options["CS"])
|
||||
|
||||
# Showing results
|
||||
self.result.clear()
|
||||
for r in results:
|
||||
index = model.getIndexByID(r)
|
||||
if not index.isValid():
|
||||
continue
|
||||
item = index.internalPointer()
|
||||
i = QListWidgetItem(item.title(), self.result)
|
||||
i.setData(Qt.UserRole, r)
|
||||
i.setData(Qt.UserRole + 1, item.path())
|
||||
self.result.addItem(i)
|
||||
|
||||
# Removing override cursor
|
||||
qApp.restoreOverrideCursor()
|
||||
|
||||
def openItem(self, item):
|
||||
mw = mainWindow()
|
||||
index = mw.mdlOutline.getIndexByID(item.data(Qt.UserRole))
|
||||
mw.mainEditor.setCurrentModelIndex(index, newTab=True)
|
||||
|
||||
|
||||
class listResultDelegate(QStyledItemDelegate):
|
||||
def __init__(self, parent=None):
|
||||
QStyledItemDelegate.__init__(self, parent)
|
||||
|
||||
def paint(self, painter, option, index):
|
||||
extra = index.data(Qt.UserRole+1)
|
||||
if not extra:
|
||||
return QStyledItemDelegate.paint(self, painter, option, index)
|
||||
|
||||
else:
|
||||
if option.state & QStyle.State_Selected:
|
||||
painter.fillRect(option.rect, option.palette.color(QPalette.Highlight))
|
||||
|
||||
title = index.data()
|
||||
extra = " - {}".format(extra)
|
||||
painter.drawText(option.rect.adjusted(2, 1, 0, 0), Qt.AlignLeft, title)
|
||||
|
||||
fm = QFontMetrics(option.font)
|
||||
w = fm.width(title)
|
||||
r = QRect(option.rect)
|
||||
r.setLeft(r.left() + w)
|
||||
painter.save()
|
||||
if option.state & QStyle.State_Selected:
|
||||
painter.setPen(Qt.white)
|
||||
else:
|
||||
painter.setPen(Qt.gray)
|
||||
painter.drawText(r.adjusted(2, 1, 0, 0), Qt.AlignLeft, extra)
|
||||
painter.restore()
|
42
src/ui/search_ui.py
Normal file
42
src/ui/search_ui.py
Normal file
|
@ -0,0 +1,42 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Form implementation generated from reading ui file 'src/ui/search_ui.ui'
|
||||
#
|
||||
# Created by: PyQt5 UI code generator 5.4.1
|
||||
#
|
||||
# WARNING! All changes made in this file will be lost!
|
||||
|
||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||
|
||||
class Ui_search(object):
|
||||
def setupUi(self, search):
|
||||
search.setObjectName("search")
|
||||
search.resize(400, 300)
|
||||
self.verticalLayout = QtWidgets.QVBoxLayout(search)
|
||||
self.verticalLayout.setContentsMargins(0, 0, 0, 0)
|
||||
self.verticalLayout.setObjectName("verticalLayout")
|
||||
self.horizontalLayout = QtWidgets.QHBoxLayout()
|
||||
self.horizontalLayout.setObjectName("horizontalLayout")
|
||||
self.text = QtWidgets.QLineEdit(search)
|
||||
self.text.setProperty("clearButtonEnabled", True)
|
||||
self.text.setObjectName("text")
|
||||
self.horizontalLayout.addWidget(self.text)
|
||||
self.btnOptions = QtWidgets.QPushButton(search)
|
||||
self.btnOptions.setText("")
|
||||
icon = QtGui.QIcon.fromTheme("edit-find")
|
||||
self.btnOptions.setIcon(icon)
|
||||
self.btnOptions.setCheckable(True)
|
||||
self.btnOptions.setObjectName("btnOptions")
|
||||
self.horizontalLayout.addWidget(self.btnOptions)
|
||||
self.verticalLayout.addLayout(self.horizontalLayout)
|
||||
self.result = QtWidgets.QListWidget(search)
|
||||
self.result.setObjectName("result")
|
||||
self.verticalLayout.addWidget(self.result)
|
||||
|
||||
self.retranslateUi(search)
|
||||
QtCore.QMetaObject.connectSlotsByName(search)
|
||||
|
||||
def retranslateUi(self, search):
|
||||
_translate = QtCore.QCoreApplication.translate
|
||||
search.setWindowTitle(_translate("search", "Form"))
|
||||
|
51
src/ui/search_ui.ui
Normal file
51
src/ui/search_ui.ui
Normal file
|
@ -0,0 +1,51 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>search</class>
|
||||
<widget class="QWidget" name="search">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>300</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="margin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="text">
|
||||
<property name="clearButtonEnabled" stdset="0">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnOptions">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="edit-find"/>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QListWidget" name="result"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
Loading…
Reference in a new issue