diff --git a/src/models/outlineModel.py b/src/models/outlineModel.py index 53c889c1..0d2ef54a 100644 --- a/src/models/outlineModel.py +++ b/src/models/outlineModel.py @@ -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 \ No newline at end of file diff --git a/src/models/persosModel.py b/src/models/persosModel.py index 270485bf..6fc8e400 100644 --- a/src/models/persosModel.py +++ b/src/models/persosModel.py @@ -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()): diff --git a/src/models/references.py b/src/models/references.py index c6b55e6d..3b9543c9 100644 --- a/src/models/references.py +++ b/src/models/references.py @@ -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 += "
  • {text}".format( diff --git a/src/ui/cheatSheet.py b/src/ui/cheatSheet.py index 6b393a2e..8bd0feaf 100644 --- a/src/ui/cheatSheet.py +++ b/src/ui/cheatSheet.py @@ -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) diff --git a/src/ui/mainWindow.py b/src/ui/mainWindow.py index 4206bb6a..60deaaca 100644 --- a/src/ui/mainWindow.py +++ b/src/ui/mainWindow.py @@ -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 diff --git a/src/ui/mainWindow.ui b/src/ui/mainWindow.ui index aa56cd58..5e89f523 100644 --- a/src/ui/mainWindow.ui +++ b/src/ui/mainWindow.ui @@ -717,7 +717,7 @@ - 3 + 0 @@ -1628,9 +1628,6 @@ true - - 0 - @@ -1644,6 +1641,34 @@ + + + + + 75 + true + + + + Search + + + true + + + + + + + 50 + false + + + + + + + @@ -2045,6 +2070,12 @@
    ui.collapsibleGroupBox2.h
    1 + + search + QWidget +
    ui.search.h
    + 1 +
    @@ -2055,8 +2086,8 @@ setVisible(bool) - 325 - 787 + 342 + 760 860 @@ -2087,12 +2118,12 @@ setVisible(bool) - 1088 - 770 + 1136 + 768 - 1053 - 731 + 1137 + 729 @@ -2135,12 +2166,12 @@ setVisible(bool) - 742 - 762 + 446 + 127 - 742 - 749 + 446 + 120 diff --git a/src/ui/search.py b/src/ui/search.py new file mode 100644 index 00000000..9858541c --- /dev/null +++ b/src/ui/search.py @@ -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() \ No newline at end of file diff --git a/src/ui/search_ui.py b/src/ui/search_ui.py new file mode 100644 index 00000000..cfc0f8c9 --- /dev/null +++ b/src/ui/search_ui.py @@ -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")) + diff --git a/src/ui/search_ui.ui b/src/ui/search_ui.ui new file mode 100644 index 00000000..e594f9ab --- /dev/null +++ b/src/ui/search_ui.ui @@ -0,0 +1,51 @@ + + + search + + + + 0 + 0 + 400 + 300 + + + + Form + + + + 0 + + + + + + + true + + + + + + + + + + + + + true + + + + + + + + + + + + +