mirror of
https://gitee.com/vnotex/vnote.git
synced 2025-07-05 13:59:52 +08:00
support search
- Ctrl+E C to toggle the search dock;
This commit is contained in:
parent
d404360fee
commit
a2ee5413a1
@ -75,7 +75,7 @@ void VExportDialog::setupUI()
|
|||||||
// Notes to export.
|
// Notes to export.
|
||||||
m_srcCB = VUtils::getComboBox();
|
m_srcCB = VUtils::getComboBox();
|
||||||
m_srcCB->setToolTip(tr("Choose notes to export"));
|
m_srcCB->setToolTip(tr("Choose notes to export"));
|
||||||
m_srcCB->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLengthWithIcon);
|
m_srcCB->setSizeAdjustPolicy(QComboBox::AdjustToContents);
|
||||||
connect(m_srcCB, SIGNAL(currentIndexChanged(int)),
|
connect(m_srcCB, SIGNAL(currentIndexChanged(int)),
|
||||||
this, SLOT(handleCurrentSrcChanged(int)));
|
this, SLOT(handleCurrentSrcChanged(int)));
|
||||||
|
|
||||||
@ -580,7 +580,7 @@ void VExportDialog::startExport()
|
|||||||
|
|
||||||
if (opt.m_outputSuffix.isEmpty()
|
if (opt.m_outputSuffix.isEmpty()
|
||||||
|| opt.m_cmd.isEmpty()
|
|| opt.m_cmd.isEmpty()
|
||||||
|| opt.m_allInOne && opt.m_folderSep.isEmpty()) {
|
|| (opt.m_allInOne && opt.m_folderSep.isEmpty())) {
|
||||||
appendLogLine(tr("Invalid configurations for custom export."));
|
appendLogLine(tr("Invalid configurations for custom export."));
|
||||||
m_inExport = false;
|
m_inExport = false;
|
||||||
m_exportBtn->setEnabled(true);
|
m_exportBtn->setEnabled(true);
|
||||||
@ -1274,11 +1274,11 @@ int VExportDialog::doExportCustomAllInOne(const QList<QString> &p_files,
|
|||||||
QWidget *VExportDialog::setupCustomAdvancedSettings()
|
QWidget *VExportDialog::setupCustomAdvancedSettings()
|
||||||
{
|
{
|
||||||
// Source format.
|
// Source format.
|
||||||
m_customSrcFormatCB = VUtils::getComboBox();
|
m_customSrcFormatCB = VUtils::getComboBox(this);
|
||||||
m_customSrcFormatCB->setToolTip(tr("Choose format of the input"));
|
m_customSrcFormatCB->setToolTip(tr("Choose format of the input"));
|
||||||
|
|
||||||
// Output suffix.
|
// Output suffix.
|
||||||
m_customSuffixEdit = new VLineEdit();
|
m_customSuffixEdit = new VLineEdit(this);
|
||||||
m_customSuffixEdit->setPlaceholderText(tr("Without the preceding dot"));
|
m_customSuffixEdit->setPlaceholderText(tr("Without the preceding dot"));
|
||||||
m_customSuffixEdit->setToolTip(tr("Suffix of the output file without the preceding dot"));
|
m_customSuffixEdit->setToolTip(tr("Suffix of the output file without the preceding dot"));
|
||||||
QValidator *validator = new QRegExpValidator(QRegExp(VUtils::c_fileNameRegExp),
|
QValidator *validator = new QRegExpValidator(QRegExp(VUtils::c_fileNameRegExp),
|
||||||
@ -1288,11 +1288,12 @@ QWidget *VExportDialog::setupCustomAdvancedSettings()
|
|||||||
QLabel *tipsLabel = new QLabel(tr("<span><span style=\"font-weight:bold;\">%0</span> for the input file; "
|
QLabel *tipsLabel = new QLabel(tr("<span><span style=\"font-weight:bold;\">%0</span> for the input file; "
|
||||||
"<span style=\"font-weight:bold;\">%1</span> for the output file; "
|
"<span style=\"font-weight:bold;\">%1</span> for the output file; "
|
||||||
"<span style=\"font-weight:bold;\">%2</span> for the rendering CSS style file; "
|
"<span style=\"font-weight:bold;\">%2</span> for the rendering CSS style file; "
|
||||||
"<span style=\"font-weight:bold;\">%3</span> for the input file directory.</span>"));
|
"<span style=\"font-weight:bold;\">%3</span> for the input file directory.</span>"),
|
||||||
|
this);
|
||||||
tipsLabel->setWordWrap(true);
|
tipsLabel->setWordWrap(true);
|
||||||
|
|
||||||
// Enable All In One.
|
// Enable All In One.
|
||||||
m_customAllInOneCB = new QCheckBox(tr("Enable All In One"));
|
m_customAllInOneCB = new QCheckBox(tr("Enable All In One"), this);
|
||||||
m_customAllInOneCB->setToolTip(tr("Pass a list of input files to the custom command"));
|
m_customAllInOneCB->setToolTip(tr("Pass a list of input files to the custom command"));
|
||||||
connect(m_customAllInOneCB, &QCheckBox::stateChanged,
|
connect(m_customAllInOneCB, &QCheckBox::stateChanged,
|
||||||
this, [this](int p_state) {
|
this, [this](int p_state) {
|
||||||
@ -1302,13 +1303,13 @@ QWidget *VExportDialog::setupCustomAdvancedSettings()
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Input directory separator.
|
// Input directory separator.
|
||||||
m_customFolderSepEdit = new VLineEdit();
|
m_customFolderSepEdit = new VLineEdit(this);
|
||||||
m_customFolderSepEdit->setPlaceholderText(tr("Separator to concatenate input files directories"));
|
m_customFolderSepEdit->setPlaceholderText(tr("Separator to concatenate input files directories"));
|
||||||
m_customFolderSepEdit->setToolTip(tr("Separator to concatenate input files directories"));
|
m_customFolderSepEdit->setToolTip(tr("Separator to concatenate input files directories"));
|
||||||
m_customFolderSepEdit->setEnabled(false);
|
m_customFolderSepEdit->setEnabled(false);
|
||||||
|
|
||||||
// Target file name for all in one.
|
// Target file name for all in one.
|
||||||
m_customTargetFileNameEdit = new VLineEdit();
|
m_customTargetFileNameEdit = new VLineEdit(this);
|
||||||
m_customTargetFileNameEdit->setPlaceholderText(tr("Empty to use the name of the first source file"));
|
m_customTargetFileNameEdit->setPlaceholderText(tr("Empty to use the name of the first source file"));
|
||||||
m_customTargetFileNameEdit->setToolTip(tr("Name of the generated All-In-One file"));
|
m_customTargetFileNameEdit->setToolTip(tr("Name of the generated All-In-One file"));
|
||||||
validator = new QRegExpValidator(QRegExp(VUtils::c_fileNameRegExp),
|
validator = new QRegExpValidator(QRegExp(VUtils::c_fileNameRegExp),
|
||||||
@ -1317,7 +1318,7 @@ QWidget *VExportDialog::setupCustomAdvancedSettings()
|
|||||||
m_customTargetFileNameEdit->setEnabled(false);
|
m_customTargetFileNameEdit->setEnabled(false);
|
||||||
|
|
||||||
// Cmd edit.
|
// Cmd edit.
|
||||||
m_customCmdEdit = new QPlainTextEdit();
|
m_customCmdEdit = new QPlainTextEdit(this);
|
||||||
m_customCmdEdit->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum);
|
m_customCmdEdit->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum);
|
||||||
QString cmdExamp("pandoc --resource-path=.:\"%3\" --css=\"%2\" -s -o \"%1\" \"%0\"");
|
QString cmdExamp("pandoc --resource-path=.:\"%3\" --css=\"%2\" -s -o \"%1\" \"%0\"");
|
||||||
m_customCmdEdit->setPlaceholderText(cmdExamp);
|
m_customCmdEdit->setPlaceholderText(cmdExamp);
|
||||||
@ -1348,12 +1349,12 @@ QWidget *VExportDialog::setupCustomAdvancedSettings()
|
|||||||
QWidget *wid = new QWidget();
|
QWidget *wid = new QWidget();
|
||||||
wid->setLayout(advLayout);
|
wid->setLayout(advLayout);
|
||||||
|
|
||||||
m_customCmdEdit->setMaximumHeight(100);
|
m_customCmdEdit->setMaximumHeight(m_customSrcFormatCB->height() * 3);
|
||||||
|
|
||||||
return wid;
|
return wid;
|
||||||
}
|
}
|
||||||
|
|
||||||
int VExportDialog::outputAsHTML(QString &p_outputFolder,
|
int VExportDialog::outputAsHTML(const QString &p_outputFolder,
|
||||||
QString *p_errMsg,
|
QString *p_errMsg,
|
||||||
QList<QString> *p_outputFiles)
|
QList<QString> *p_outputFiles)
|
||||||
{
|
{
|
||||||
|
@ -368,7 +368,7 @@ private:
|
|||||||
|
|
||||||
ExportFormat currentFormat() const;
|
ExportFormat currentFormat() const;
|
||||||
|
|
||||||
int outputAsHTML(QString &p_outputFolder,
|
int outputAsHTML(const QString &p_outputFolder,
|
||||||
QString *p_errMsg = NULL,
|
QString *p_errMsg = NULL,
|
||||||
QList<QString> *p_outputFiles = NULL);
|
QList<QString> *p_outputFiles = NULL);
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ void VFindReplaceDialog::setupUI()
|
|||||||
m_replaceFindBtn->setProperty("FlatBtn", true);
|
m_replaceFindBtn->setProperty("FlatBtn", true);
|
||||||
m_replaceAllBtn = new QPushButton(tr("Replace A&ll"));
|
m_replaceAllBtn = new QPushButton(tr("Replace A&ll"));
|
||||||
m_replaceAllBtn->setProperty("FlatBtn", true);
|
m_replaceAllBtn->setProperty("FlatBtn", true);
|
||||||
m_advancedBtn = new QPushButton(tr("&Advanced >>"));
|
m_advancedBtn = new QPushButton(tr("&Advanced >>>"));
|
||||||
m_advancedBtn->setProperty("FlatBtn", true);
|
m_advancedBtn->setProperty("FlatBtn", true);
|
||||||
m_advancedBtn->setCheckable(true);
|
m_advancedBtn->setCheckable(true);
|
||||||
|
|
||||||
@ -199,9 +199,9 @@ void VFindReplaceDialog::handleFindTextChanged(const QString &p_text)
|
|||||||
void VFindReplaceDialog::advancedBtnToggled(bool p_checked)
|
void VFindReplaceDialog::advancedBtnToggled(bool p_checked)
|
||||||
{
|
{
|
||||||
if (p_checked) {
|
if (p_checked) {
|
||||||
m_advancedBtn->setText("B&asic <<");
|
m_advancedBtn->setText(tr("B&asic <<<"));
|
||||||
} else {
|
} else {
|
||||||
m_advancedBtn->setText("&Advanced <<");
|
m_advancedBtn->setText(tr("&Advanced >>>"));
|
||||||
}
|
}
|
||||||
|
|
||||||
m_caseSensitiveCheck->setVisible(p_checked);
|
m_caseSensitiveCheck->setVisible(p_checked);
|
||||||
|
@ -48,6 +48,7 @@ private slots:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void setupUI();
|
void setupUI();
|
||||||
|
|
||||||
// Bit OR of FindOption
|
// Bit OR of FindOption
|
||||||
uint m_options;
|
uint m_options;
|
||||||
bool m_replaceAvailable;
|
bool m_replaceAvailable;
|
||||||
|
34
src/isearchengine.h
Normal file
34
src/isearchengine.h
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
#ifndef ISEARCHENGINE_H
|
||||||
|
#define ISEARCHENGINE_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QVector>
|
||||||
|
|
||||||
|
#include "vsearchconfig.h"
|
||||||
|
|
||||||
|
// Abstract class for search engine.
|
||||||
|
class ISearchEngine : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit ISearchEngine(QObject *p_parent = nullptr)
|
||||||
|
: QObject(p_parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void search(const QSharedPointer<VSearchConfig> &p_config,
|
||||||
|
const QSharedPointer<VSearchResult> &p_result) = 0;
|
||||||
|
|
||||||
|
virtual void stop() = 0;
|
||||||
|
|
||||||
|
virtual void clear() = 0;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void finished(const QSharedPointer<VSearchResult> &p_result);
|
||||||
|
|
||||||
|
void resultItemAdded(const QSharedPointer<VSearchResultItem> &p_item);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
QSharedPointer<VSearchResult> m_result;
|
||||||
|
};
|
||||||
|
#endif // ISEARCHENGINE_H
|
10
src/resources/icons/clear_search.svg
Normal file
10
src/resources/icons/clear_search.svg
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.2.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
width="512px" height="512px" viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
|
||||||
|
<path style="fill:#C9302C" d="M443.6,387.1L312.4,255.4l131.5-130c5.4-5.4,5.4-14.2,0-19.6l-37.4-37.6c-2.6-2.6-6.1-4-9.8-4c-3.7,0-7.2,1.5-9.8,4
|
||||||
|
L256,197.8L124.9,68.3c-2.6-2.6-6.1-4-9.8-4c-3.7,0-7.2,1.5-9.8,4L68,105.9c-5.4,5.4-5.4,14.2,0,19.6l131.5,130L68.4,387.1
|
||||||
|
c-2.6,2.6-4.1,6.1-4.1,9.8c0,3.7,1.4,7.2,4.1,9.8l37.4,37.6c2.7,2.7,6.2,4.1,9.8,4.1c3.5,0,7.1-1.3,9.8-4.1L256,313.1l130.7,131.1
|
||||||
|
c2.7,2.7,6.2,4.1,9.8,4.1c3.5,0,7.1-1.3,9.8-4.1l37.4-37.6c2.6-2.6,4.1-6.1,4.1-9.8C447.7,393.2,446.2,389.7,443.6,387.1z"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 995 B |
15
src/resources/icons/note_item.svg
Normal file
15
src/resources/icons/note_item.svg
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.2.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
width="512px" height="512px" viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<path style="fill:#000000" d="M398.6,169.2c-0.9-2.2-2-4.3-3.5-6.1l-83.8-91.7c-1.9-2.1-4.2-3.6-6.7-4.9c-2.9-1.5-6.1-2.1-9.5-2.1H135.2
|
||||||
|
c-12.4,0-22.7,10.6-22.7,23.9v335.2c0,13.4,10.3,24.9,22.7,24.9h243.1c12.4,0,22.2-11.5,22.2-24.9V179.4
|
||||||
|
C400.5,175.8,400,172.3,398.6,169.2z M160.5,178.6c0-1.5,1.8-2.1,3.4-2.1h70.8c1.6,0,2.8,0.6,2.8,2.1v10.8c0,1.4-1.1,3.1-2.8,3.1
|
||||||
|
h-70.8c-1.6,0-3.4-1.7-3.4-3.1V178.6z M160.5,306.6c0-1.5,1.8-2.1,3.4-2.1h122.2c1.6,0,2.4,0.6,2.4,2.1v10.8c0,1.4-0.7,3.1-2.4,3.1
|
||||||
|
H163.9c-1.6,0-3.4-1.7-3.4-3.1V306.6z M320.5,381.4c0,1.4-0.7,3.1-2.4,3.1H163.9c-1.6,0-3.4-1.7-3.4-3.1v-10.8
|
||||||
|
c0-1.5,1.8-2.1,3.4-2.1h154.2c1.6,0,2.4,0.6,2.4,2.1V381.4z M352.5,253.4c0,1.4-0.7,3.1-2.4,3.1H163.9c-1.6,0-3.4-1.7-3.4-3.1
|
||||||
|
v-10.8c0-1.5,1.8-2.1,3.4-2.1h186.2c1.6,0,2.4,0.6,2.4,2.1V253.4z M305.6,177.5c-5.6,0-11.1-5.2-11.1-11.3v-66l71.2,77.3H305.6z"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.3 KiB |
10
src/resources/icons/search.svg
Normal file
10
src/resources/icons/search.svg
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.2.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
width="512px" height="512px" viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
|
||||||
|
<path style="fill:#000000" d="M445,386.7l-84.8-85.9c13.8-24.1,21-50.9,21-77.9c0-87.6-71.2-158.9-158.6-158.9C135.2,64,64,135.3,64,222.9
|
||||||
|
c0,87.6,71.2,158.9,158.6,158.9c27.9,0,55.5-7.7,80.1-22.4l84.4,85.6c1.9,1.9,4.6,3.1,7.3,3.1c2.7,0,5.4-1.1,7.3-3.1l43.3-43.8
|
||||||
|
C449,397.1,449,390.7,445,386.7z M222.6,125.9c53.4,0,96.8,43.5,96.8,97c0,53.5-43.4,97-96.8,97c-53.4,0-96.8-43.5-96.8-97
|
||||||
|
C125.8,169.4,169.2,125.9,222.6,125.9z"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 905 B |
14
src/resources/icons/search_advanced.svg
Normal file
14
src/resources/icons/search_advanced.svg
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.2.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
width="512px" height="512px" viewBox="0 0 512 512" enable-background="new 0 0 512 512" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<path style="fill:#000000" d="M32,376h283.35c6.186-14.112,20.281-24,36.65-24s30.465,9.888,36.65,24H480v32h-91.35c-6.186,14.112-20.281,24-36.65,24
|
||||||
|
s-30.465-9.888-36.65-24H32"/>
|
||||||
|
<path style="fill:#000000" d="M32,240h91.35c6.186-14.112,20.281-24,36.65-24s30.465,9.888,36.65,24H480v32H196.65c-6.186,14.112-20.281,24-36.65,24
|
||||||
|
s-30.465-9.888-36.65-24H32"/>
|
||||||
|
<path style="fill:#000000" d="M32,104h283.35c6.186-14.112,20.281-24,36.65-24s30.465,9.888,36.65,24H480v32h-91.35c-6.186,14.112-20.281,24-36.65,24
|
||||||
|
s-30.465-9.888-36.65-24H32"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1022 B |
12
src/resources/icons/search_console.svg
Normal file
12
src/resources/icons/search_console.svg
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.2.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
width="512px" height="512px" viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<path style="fill:#000000" d="M468.7,64H43.3c-6,0-11.3,5-11.3,11.1v265.7c0,6.2,5.2,11.1,11.3,11.1h425.4c6,0,11.3-5,11.3-11.1V75.1
|
||||||
|
C480,69,474.8,64,468.7,64z M448,320H64V96h384V320z"/>
|
||||||
|
<path style="fill:#000000" d="M302.5,448c28-0.5,41.5-3.9,29-12.5c-12.5-8.7-28.5-15.3-29-22.5c-0.3-3.7-1.7-45-1.7-45H256h-44.8c0,0-1.5,41.3-1.7,45
|
||||||
|
c-0.5,7.1-16.5,13.8-29,22.5c-12.5,8.7,1,12,29,12.5H302.5z"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 890 B |
@ -183,64 +183,18 @@ QDockWidget::close-button:hover, QDockWidget::float-button:hover {
|
|||||||
/* End DockWidget */
|
/* End DockWidget */
|
||||||
|
|
||||||
/* QPushButton */
|
/* QPushButton */
|
||||||
QPushButton {
|
|
||||||
color: @pushbutton_fg;
|
|
||||||
background: @pushbutton_bg;
|
|
||||||
border: 1px solid @pushbutton_border;
|
|
||||||
padding: 3px;
|
|
||||||
min-width: 80px;
|
|
||||||
}
|
|
||||||
|
|
||||||
QPushButton:focus {
|
|
||||||
background-color: @pushbutton_focus_bg;
|
|
||||||
}
|
|
||||||
|
|
||||||
QPushButton:pressed {
|
|
||||||
background-color: @pushbutton_pressed_bg;
|
|
||||||
}
|
|
||||||
|
|
||||||
QPushButton:checked {
|
|
||||||
background-color: @pushbutton_checked_bg;
|
|
||||||
}
|
|
||||||
|
|
||||||
QPushButton:checked:hover {
|
|
||||||
background-color: @pushbutton_hover_bg;
|
|
||||||
}
|
|
||||||
|
|
||||||
QPushButton:hover {
|
|
||||||
background-color: @pushbutton_hover_bg;
|
|
||||||
}
|
|
||||||
|
|
||||||
QPushButton:flat {
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
QPushButton:default {
|
|
||||||
border: 1px solid @pushbutton_default_border;
|
|
||||||
}
|
|
||||||
|
|
||||||
QPushButton:disabled {
|
|
||||||
color: @pushbutton_disabled_fg;
|
|
||||||
background-color: @pushbutton_disabled_bg;
|
|
||||||
}
|
|
||||||
|
|
||||||
QPushButton::menu-indicator {
|
|
||||||
image: url(arrow_dropdown.svg);
|
|
||||||
width: 16px;
|
|
||||||
height: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
QPushButton[SpecialBtn="true"] {
|
QPushButton[SpecialBtn="true"] {
|
||||||
color: @pushbutton_specialbtn_fg;
|
color: @pushbutton_specialbtn_fg;
|
||||||
background: @pushbutton_specialbtn_bg;
|
background: @pushbutton_specialbtn_bg;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPushButton[SpecialBtn="true"]:focus {
|
QPushButton[SpecialBtn="true"]:default {
|
||||||
background-color: @pushbutton_specialbtn_focus_bg;
|
border: 1px solid @pushbutton_default_border;
|
||||||
|
background-color: @pushbutton_specialbtn_bg;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPushButton[SpecialBtn="true"]:pressed {
|
QPushButton[SpecialBtn="true"]:focus {
|
||||||
background-color: @pushbutton_specialbtn_pressed_bg;
|
background-color: @pushbutton_specialbtn_focus_bg;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPushButton[SpecialBtn="true"]:checked {
|
QPushButton[SpecialBtn="true"]:checked {
|
||||||
@ -255,16 +209,15 @@ QPushButton[SpecialBtn="true"]:hover {
|
|||||||
background-color: @pushbutton_specialbtn_hover_bg;
|
background-color: @pushbutton_specialbtn_hover_bg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QPushButton[SpecialBtn="true"]:pressed {
|
||||||
|
background-color: @pushbutton_specialbtn_pressed_bg;
|
||||||
|
}
|
||||||
|
|
||||||
QPushButton[SpecialBtn="true"]:disabled {
|
QPushButton[SpecialBtn="true"]:disabled {
|
||||||
color: @pushbutton_disabled_fg;
|
color: @pushbutton_disabled_fg;
|
||||||
background-color: @pushbutton_disabled_bg;
|
background-color: @pushbutton_disabled_bg;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPushButton[SpecialBtn="true"]:default {
|
|
||||||
border: 1px solid @pushbutton_default_border;
|
|
||||||
background-color: @pushbutton_specialbtn_bg;
|
|
||||||
}
|
|
||||||
|
|
||||||
QPushButton[CornerBtn="true"] {
|
QPushButton[CornerBtn="true"] {
|
||||||
padding: 4px -2px 4px -2px;
|
padding: 4px -2px 4px -2px;
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
@ -277,14 +230,19 @@ QPushButton[CornerBtn="true"]::menu-indicator {
|
|||||||
image: none;
|
image: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPushButton[CornerBtn="true"]:hover {
|
QPushButton[CornerBtn="true"]:default {
|
||||||
background-color: @pushbutton_cornerbtn_hover_bg;
|
border: 1px solid @pushbutton_default_border;
|
||||||
|
background-color: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPushButton[CornerBtn="true"]:focus {
|
QPushButton[CornerBtn="true"]:focus {
|
||||||
background-color: @pushbutton_cornerbtn_focus_bg;
|
background-color: @pushbutton_cornerbtn_focus_bg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QPushButton[CornerBtn="true"]:hover {
|
||||||
|
background-color: @pushbutton_cornerbtn_hover_bg;
|
||||||
|
}
|
||||||
|
|
||||||
QPushButton[CornerBtn="true"]:pressed {
|
QPushButton[CornerBtn="true"]:pressed {
|
||||||
background-color: @pushbutton_cornerbtn_pressed_bg;
|
background-color: @pushbutton_cornerbtn_pressed_bg;
|
||||||
}
|
}
|
||||||
@ -294,11 +252,6 @@ QPushButton[CornerBtn="true"]:disabled {
|
|||||||
background-color: @pushbutton_disabled_bg;
|
background-color: @pushbutton_disabled_bg;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPushButton[CornerBtn="true"]:default {
|
|
||||||
border: 1px solid @pushbutton_default_border;
|
|
||||||
background-color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
QPushButton[StatusBtn="true"] {
|
QPushButton[StatusBtn="true"] {
|
||||||
font: bold;
|
font: bold;
|
||||||
padding: 0px 2px 0px 2px;
|
padding: 0px 2px 0px 2px;
|
||||||
@ -308,14 +261,19 @@ QPushButton[StatusBtn="true"] {
|
|||||||
min-width: -1;
|
min-width: -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPushButton[StatusBtn="true"]:hover {
|
QPushButton[StatusBtn="true"]:default {
|
||||||
background-color: @pushbutton_statusbtn_hover_bg;
|
border: 1px solid @pushbutton_default_border;
|
||||||
|
background-color: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPushButton[StatusBtn="true"]:focus {
|
QPushButton[StatusBtn="true"]:focus {
|
||||||
background-color: @pushbutton_statusbtn_focus_bg;;
|
background-color: @pushbutton_statusbtn_focus_bg;;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QPushButton[StatusBtn="true"]:hover {
|
||||||
|
background-color: @pushbutton_statusbtn_hover_bg;
|
||||||
|
}
|
||||||
|
|
||||||
QPushButton[StatusBtn="true"]:pressed {
|
QPushButton[StatusBtn="true"]:pressed {
|
||||||
background-color: @pushbutton_statusbtn_pressed_bg;
|
background-color: @pushbutton_statusbtn_pressed_bg;
|
||||||
}
|
}
|
||||||
@ -325,11 +283,6 @@ QPushButton[StatusBtn="true"]:disabled {
|
|||||||
background-color: @pushbutton_disabled_bg;
|
background-color: @pushbutton_disabled_bg;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPushButton[StatusBtn="true"]:default {
|
|
||||||
border: 1px solid @pushbutton_default_border;
|
|
||||||
background-color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
QPushButton[FlatBtn="true"] {
|
QPushButton[FlatBtn="true"] {
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
@ -338,14 +291,19 @@ QPushButton[FlatBtn="true"] {
|
|||||||
min-width: -1;
|
min-width: -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPushButton[FlatBtn="true"]:hover {
|
QPushButton[FlatBtn="true"]:default {
|
||||||
background-color: @pushbutton_flatbtn_hover_bg;
|
border: 1px solid @pushbutton_default_border;
|
||||||
|
background-color: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPushButton[FlatBtn="true"]:focus {
|
QPushButton[FlatBtn="true"]:focus {
|
||||||
background-color: @pushbutton_flatbtn_focus_bg;
|
background-color: @pushbutton_flatbtn_focus_bg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QPushButton[FlatBtn="true"]:hover {
|
||||||
|
background-color: @pushbutton_flatbtn_hover_bg;
|
||||||
|
}
|
||||||
|
|
||||||
QPushButton[FlatBtn="true"]:pressed {
|
QPushButton[FlatBtn="true"]:pressed {
|
||||||
background-color: @pushbutton_flatbtn_pressed_bg;
|
background-color: @pushbutton_flatbtn_pressed_bg;
|
||||||
}
|
}
|
||||||
@ -355,11 +313,6 @@ QPushButton[FlatBtn="true"]:disabled {
|
|||||||
background-color: @pushbutton_disabled_bg;
|
background-color: @pushbutton_disabled_bg;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPushButton[FlatBtn="true"]:default {
|
|
||||||
border: 1px solid @pushbutton_default_border;
|
|
||||||
background-color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
QPushButton[SelectionBtn="true"] {
|
QPushButton[SelectionBtn="true"] {
|
||||||
padding: 4px 10px 4px 10px;
|
padding: 4px 10px 4px 10px;
|
||||||
border: none;
|
border: none;
|
||||||
@ -369,14 +322,19 @@ QPushButton[SelectionBtn="true"] {
|
|||||||
min-width: -1;
|
min-width: -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPushButton[SelectionBtn="true"]:hover {
|
QPushButton[SelectionBtn="true"]:default {
|
||||||
background-color: @pushbutton_selectionbtn_hover_bg;
|
border: 1px solid @pushbutton_default_border;
|
||||||
|
background-color: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPushButton[SelectionBtn="true"]:focus {
|
QPushButton[SelectionBtn="true"]:focus {
|
||||||
background-color: @pushbutton_selectionbtn_focus_bg;
|
background-color: @pushbutton_selectionbtn_focus_bg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QPushButton[SelectionBtn="true"]:hover {
|
||||||
|
background-color: @pushbutton_selectionbtn_hover_bg;
|
||||||
|
}
|
||||||
|
|
||||||
QPushButton[SelectionBtn="true"]:pressed {
|
QPushButton[SelectionBtn="true"]:pressed {
|
||||||
background-color: @pushbutton_selectionbtn_pressed_bg;
|
background-color: @pushbutton_selectionbtn_pressed_bg;
|
||||||
}
|
}
|
||||||
@ -386,11 +344,6 @@ QPushButton[SelectionBtn="true"]:disabled {
|
|||||||
background-color: @pushbutton_disabled_bg;
|
background-color: @pushbutton_disabled_bg;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPushButton[SelectionBtn="true"]:default {
|
|
||||||
border: 1px solid @pushbutton_default_border;
|
|
||||||
background-color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
QPushButton[TitleBtn="true"] {
|
QPushButton[TitleBtn="true"] {
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
@ -399,14 +352,19 @@ QPushButton[TitleBtn="true"] {
|
|||||||
min-width: -1;
|
min-width: -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPushButton[TitleBtn="true"]:hover {
|
QPushButton[TitleBtn="true"]:default {
|
||||||
background-color: @pushbutton_titlebtn_hover_bg;
|
border: 1px solid @pushbutton_default_border;
|
||||||
|
background-color: @pushbutton_titlebtn_bg;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPushButton[TitleBtn="true"]:focus {
|
QPushButton[TitleBtn="true"]:focus {
|
||||||
background-color: @pushbutton_titlebtn_focus_bg;
|
background-color: @pushbutton_titlebtn_focus_bg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QPushButton[TitleBtn="true"]:hover {
|
||||||
|
background-color: @pushbutton_titlebtn_hover_bg;
|
||||||
|
}
|
||||||
|
|
||||||
QPushButton[TitleBtn="true"]:pressed {
|
QPushButton[TitleBtn="true"]:pressed {
|
||||||
background-color: @pushbutton_titlebtn_pressed_bg;
|
background-color: @pushbutton_titlebtn_pressed_bg;
|
||||||
}
|
}
|
||||||
@ -416,11 +374,6 @@ QPushButton[TitleBtn="true"]:disabled {
|
|||||||
background-color: @pushbutton_disabled_bg;
|
background-color: @pushbutton_disabled_bg;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPushButton[TitleBtn="true"]:default {
|
|
||||||
border: 1px solid @pushbutton_default_border;
|
|
||||||
background-color: @pushbutton_titlebtn_bg;
|
|
||||||
}
|
|
||||||
|
|
||||||
QPushButton[DangerBtn="true"] {
|
QPushButton[DangerBtn="true"] {
|
||||||
color: @pushbutton_dangerbtn_fg;
|
color: @pushbutton_dangerbtn_fg;
|
||||||
border: none;
|
border: none;
|
||||||
@ -428,14 +381,23 @@ QPushButton[DangerBtn="true"] {
|
|||||||
min-width: -1;
|
min-width: -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPushButton[DangerBtn="true"]:hover {
|
QPushButton[DangerBtn="true"]:default {
|
||||||
background-color: @pushbutton_dangerbtn_hover_bg;
|
border: 1px solid @pushbutton_default_border;
|
||||||
|
background-color: @pushbutton_dangerbtn_bg;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPushButton[DangerBtn="true"]:focus {
|
QPushButton[DangerBtn="true"]:focus {
|
||||||
background-color: @pushbutton_dangerbtn_focus_bg;
|
background-color: @pushbutton_dangerbtn_focus_bg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QPushButton[DangerBtn="true"]:checked {
|
||||||
|
background-color: @pushbutton_dangerbtn_pressed_bg;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPushButton[DangerBtn="true"]:hover {
|
||||||
|
background-color: @pushbutton_dangerbtn_hover_bg;
|
||||||
|
}
|
||||||
|
|
||||||
QPushButton[DangerBtn="true"]:pressed {
|
QPushButton[DangerBtn="true"]:pressed {
|
||||||
background-color: @pushbutton_dangerbtn_pressed_bg;
|
background-color: @pushbutton_dangerbtn_pressed_bg;
|
||||||
}
|
}
|
||||||
@ -445,11 +407,6 @@ QPushButton[DangerBtn="true"]:disabled {
|
|||||||
background-color: @pushbutton_disabled_bg;
|
background-color: @pushbutton_disabled_bg;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPushButton[DangerBtn="true"]:default {
|
|
||||||
border: 1px solid @pushbutton_default_border;
|
|
||||||
background-color: @pushbutton_dangerbtn_bg;
|
|
||||||
}
|
|
||||||
|
|
||||||
QPushButton[ToolBoxActiveBtn="true"] {
|
QPushButton[ToolBoxActiveBtn="true"] {
|
||||||
padding: 4px 10px 4px 4px;
|
padding: 4px 10px 4px 4px;
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
@ -459,6 +416,11 @@ QPushButton[ToolBoxActiveBtn="true"] {
|
|||||||
min-width: -1;
|
min-width: -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QPushButton[ToolBoxActiveBtn="true"]:default {
|
||||||
|
border: 1px solid @pushbutton_default_border;
|
||||||
|
background-color: @pushbutton_toolboxbtn_active_bg;
|
||||||
|
}
|
||||||
|
|
||||||
QPushButton[ToolBoxActiveBtn="true"]:focus {
|
QPushButton[ToolBoxActiveBtn="true"]:focus {
|
||||||
background-color: @pushbutton_toolboxbtn_active_focus_bg;
|
background-color: @pushbutton_toolboxbtn_active_focus_bg;
|
||||||
}
|
}
|
||||||
@ -476,11 +438,6 @@ QPushButton[ToolBoxActiveBtn="true"]:disabled {
|
|||||||
background-color: @pushbutton_disabled_bg;
|
background-color: @pushbutton_disabled_bg;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPushButton[ToolBoxActiveBtn="true"]:default {
|
|
||||||
border: 1px solid @pushbutton_default_border;
|
|
||||||
background-color: @pushbutton_toolboxbtn_active_bg;
|
|
||||||
}
|
|
||||||
|
|
||||||
QPushButton[AvatarBtn="true"] {
|
QPushButton[AvatarBtn="true"] {
|
||||||
padding: 2px 4px 2px 4px;
|
padding: 2px 4px 2px 4px;
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
@ -489,14 +446,19 @@ QPushButton[AvatarBtn="true"] {
|
|||||||
min-width: -1;
|
min-width: -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPushButton[AvatarBtn="true"]:hover {
|
QPushButton[AvatarBtn="true"]:default {
|
||||||
background-color: @pushbutton_avatarbtn_hover_bg;
|
border: 1px solid @pushbutton_default_border;
|
||||||
|
background-color: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPushButton[AvatarBtn="true"]:focus {
|
QPushButton[AvatarBtn="true"]:focus {
|
||||||
background-color: @pushbutton_avatarbtn_focus_bg;;
|
background-color: @pushbutton_avatarbtn_focus_bg;;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QPushButton[AvatarBtn="true"]:hover {
|
||||||
|
background-color: @pushbutton_avatarbtn_hover_bg;
|
||||||
|
}
|
||||||
|
|
||||||
QPushButton[AvatarBtn="true"]:pressed {
|
QPushButton[AvatarBtn="true"]:pressed {
|
||||||
background-color: @pushbutton_avatarbtn_pressed_bg;
|
background-color: @pushbutton_avatarbtn_pressed_bg;
|
||||||
}
|
}
|
||||||
@ -506,9 +468,51 @@ QPushButton[AvatarBtn="true"]:disabled {
|
|||||||
background-color: @pushbutton_disabled_bg;
|
background-color: @pushbutton_disabled_bg;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPushButton[AvatarBtn="true"]:default {
|
QPushButton {
|
||||||
|
color: @pushbutton_fg;
|
||||||
|
background: @pushbutton_bg;
|
||||||
|
border: 1px solid @pushbutton_border;
|
||||||
|
padding: 3px;
|
||||||
|
min-width: 80px;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPushButton:default {
|
||||||
border: 1px solid @pushbutton_default_border;
|
border: 1px solid @pushbutton_default_border;
|
||||||
background-color: transparent;
|
}
|
||||||
|
|
||||||
|
QPushButton:focus {
|
||||||
|
background-color: @pushbutton_focus_bg;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPushButton:checked {
|
||||||
|
background-color: @pushbutton_checked_bg;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPushButton:checked:hover {
|
||||||
|
background-color: @pushbutton_hover_bg;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPushButton:flat {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPushButton:hover {
|
||||||
|
background-color: @pushbutton_hover_bg;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPushButton:pressed {
|
||||||
|
background-color: @pushbutton_pressed_bg;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPushButton:disabled {
|
||||||
|
color: @pushbutton_disabled_fg;
|
||||||
|
background-color: @pushbutton_disabled_bg;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPushButton::menu-indicator {
|
||||||
|
image: url(arrow_dropdown.svg);
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
VButtonMenuItem {
|
VButtonMenuItem {
|
||||||
@ -544,11 +548,11 @@ VButtonMenuItem[Heading6="true"] {
|
|||||||
font-size: 14pt;
|
font-size: 14pt;
|
||||||
}
|
}
|
||||||
|
|
||||||
VButtonMenuItem:hover {
|
VButtonMenuItem:focus {
|
||||||
background-color: @menubar_item_selected_bg;
|
background-color: @menubar_item_selected_bg;
|
||||||
}
|
}
|
||||||
|
|
||||||
VButtonMenuItem:focus {
|
VButtonMenuItem:hover {
|
||||||
background-color: @menubar_item_selected_bg;
|
background-color: @menubar_item_selected_bg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,64 +183,18 @@ QDockWidget::close-button:hover, QDockWidget::float-button:hover {
|
|||||||
/* End DockWidget */
|
/* End DockWidget */
|
||||||
|
|
||||||
/* QPushButton */
|
/* QPushButton */
|
||||||
QPushButton {
|
|
||||||
color: @pushbutton_fg;
|
|
||||||
background: @pushbutton_bg;
|
|
||||||
border: 1px solid @pushbutton_border;
|
|
||||||
padding: 3px;
|
|
||||||
min-width: 80px;
|
|
||||||
}
|
|
||||||
|
|
||||||
QPushButton:focus {
|
|
||||||
background-color: @pushbutton_focus_bg;
|
|
||||||
}
|
|
||||||
|
|
||||||
QPushButton:pressed {
|
|
||||||
background-color: @pushbutton_pressed_bg;
|
|
||||||
}
|
|
||||||
|
|
||||||
QPushButton:checked {
|
|
||||||
background-color: @pushbutton_checked_bg;
|
|
||||||
}
|
|
||||||
|
|
||||||
QPushButton:checked:hover {
|
|
||||||
background-color: @pushbutton_hover_bg;
|
|
||||||
}
|
|
||||||
|
|
||||||
QPushButton:hover {
|
|
||||||
background-color: @pushbutton_hover_bg;
|
|
||||||
}
|
|
||||||
|
|
||||||
QPushButton:flat {
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
QPushButton:default {
|
|
||||||
border: 1px solid @pushbutton_default_border;
|
|
||||||
}
|
|
||||||
|
|
||||||
QPushButton:disabled {
|
|
||||||
color: @pushbutton_disabled_fg;
|
|
||||||
background-color: @pushbutton_disabled_bg;
|
|
||||||
}
|
|
||||||
|
|
||||||
QPushButton::menu-indicator {
|
|
||||||
image: url(arrow_dropdown.svg);
|
|
||||||
width: 16px;
|
|
||||||
height: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
QPushButton[SpecialBtn="true"] {
|
QPushButton[SpecialBtn="true"] {
|
||||||
color: @pushbutton_specialbtn_fg;
|
color: @pushbutton_specialbtn_fg;
|
||||||
background: @pushbutton_specialbtn_bg;
|
background: @pushbutton_specialbtn_bg;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPushButton[SpecialBtn="true"]:focus {
|
QPushButton[SpecialBtn="true"]:default {
|
||||||
background-color: @pushbutton_specialbtn_focus_bg;
|
border: 1px solid @pushbutton_default_border;
|
||||||
|
background-color: @pushbutton_specialbtn_bg;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPushButton[SpecialBtn="true"]:pressed {
|
QPushButton[SpecialBtn="true"]:focus {
|
||||||
background-color: @pushbutton_specialbtn_pressed_bg;
|
background-color: @pushbutton_specialbtn_focus_bg;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPushButton[SpecialBtn="true"]:checked {
|
QPushButton[SpecialBtn="true"]:checked {
|
||||||
@ -255,16 +209,15 @@ QPushButton[SpecialBtn="true"]:hover {
|
|||||||
background-color: @pushbutton_specialbtn_hover_bg;
|
background-color: @pushbutton_specialbtn_hover_bg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QPushButton[SpecialBtn="true"]:pressed {
|
||||||
|
background-color: @pushbutton_specialbtn_pressed_bg;
|
||||||
|
}
|
||||||
|
|
||||||
QPushButton[SpecialBtn="true"]:disabled {
|
QPushButton[SpecialBtn="true"]:disabled {
|
||||||
color: @pushbutton_disabled_fg;
|
color: @pushbutton_disabled_fg;
|
||||||
background-color: @pushbutton_disabled_bg;
|
background-color: @pushbutton_disabled_bg;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPushButton[SpecialBtn="true"]:default {
|
|
||||||
border: 1px solid @pushbutton_default_border;
|
|
||||||
background-color: @pushbutton_specialbtn_bg;
|
|
||||||
}
|
|
||||||
|
|
||||||
QPushButton[CornerBtn="true"] {
|
QPushButton[CornerBtn="true"] {
|
||||||
padding: 4px -2px 4px -2px;
|
padding: 4px -2px 4px -2px;
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
@ -277,14 +230,19 @@ QPushButton[CornerBtn="true"]::menu-indicator {
|
|||||||
image: none;
|
image: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPushButton[CornerBtn="true"]:hover {
|
QPushButton[CornerBtn="true"]:default {
|
||||||
background-color: @pushbutton_cornerbtn_hover_bg;
|
border: 1px solid @pushbutton_default_border;
|
||||||
|
background-color: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPushButton[CornerBtn="true"]:focus {
|
QPushButton[CornerBtn="true"]:focus {
|
||||||
background-color: @pushbutton_cornerbtn_focus_bg;
|
background-color: @pushbutton_cornerbtn_focus_bg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QPushButton[CornerBtn="true"]:hover {
|
||||||
|
background-color: @pushbutton_cornerbtn_hover_bg;
|
||||||
|
}
|
||||||
|
|
||||||
QPushButton[CornerBtn="true"]:pressed {
|
QPushButton[CornerBtn="true"]:pressed {
|
||||||
background-color: @pushbutton_cornerbtn_pressed_bg;
|
background-color: @pushbutton_cornerbtn_pressed_bg;
|
||||||
}
|
}
|
||||||
@ -294,11 +252,6 @@ QPushButton[CornerBtn="true"]:disabled {
|
|||||||
background-color: @pushbutton_disabled_bg;
|
background-color: @pushbutton_disabled_bg;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPushButton[CornerBtn="true"]:default {
|
|
||||||
border: 1px solid @pushbutton_default_border;
|
|
||||||
background-color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
QPushButton[StatusBtn="true"] {
|
QPushButton[StatusBtn="true"] {
|
||||||
font: bold;
|
font: bold;
|
||||||
padding: 0px 2px 0px 2px;
|
padding: 0px 2px 0px 2px;
|
||||||
@ -308,14 +261,19 @@ QPushButton[StatusBtn="true"] {
|
|||||||
min-width: -1;
|
min-width: -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPushButton[StatusBtn="true"]:hover {
|
QPushButton[StatusBtn="true"]:default {
|
||||||
background-color: @pushbutton_statusbtn_hover_bg;
|
border: 1px solid @pushbutton_default_border;
|
||||||
|
background-color: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPushButton[StatusBtn="true"]:focus {
|
QPushButton[StatusBtn="true"]:focus {
|
||||||
background-color: @pushbutton_statusbtn_focus_bg;;
|
background-color: @pushbutton_statusbtn_focus_bg;;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QPushButton[StatusBtn="true"]:hover {
|
||||||
|
background-color: @pushbutton_statusbtn_hover_bg;
|
||||||
|
}
|
||||||
|
|
||||||
QPushButton[StatusBtn="true"]:pressed {
|
QPushButton[StatusBtn="true"]:pressed {
|
||||||
background-color: @pushbutton_statusbtn_pressed_bg;
|
background-color: @pushbutton_statusbtn_pressed_bg;
|
||||||
}
|
}
|
||||||
@ -325,11 +283,6 @@ QPushButton[StatusBtn="true"]:disabled {
|
|||||||
background-color: @pushbutton_disabled_bg;
|
background-color: @pushbutton_disabled_bg;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPushButton[StatusBtn="true"]:default {
|
|
||||||
border: 1px solid @pushbutton_default_border;
|
|
||||||
background-color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
QPushButton[FlatBtn="true"] {
|
QPushButton[FlatBtn="true"] {
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
@ -338,14 +291,19 @@ QPushButton[FlatBtn="true"] {
|
|||||||
min-width: -1;
|
min-width: -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPushButton[FlatBtn="true"]:hover {
|
QPushButton[FlatBtn="true"]:default {
|
||||||
background-color: @pushbutton_flatbtn_hover_bg;
|
border: 1px solid @pushbutton_default_border;
|
||||||
|
background-color: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPushButton[FlatBtn="true"]:focus {
|
QPushButton[FlatBtn="true"]:focus {
|
||||||
background-color: @pushbutton_flatbtn_focus_bg;
|
background-color: @pushbutton_flatbtn_focus_bg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QPushButton[FlatBtn="true"]:hover {
|
||||||
|
background-color: @pushbutton_flatbtn_hover_bg;
|
||||||
|
}
|
||||||
|
|
||||||
QPushButton[FlatBtn="true"]:pressed {
|
QPushButton[FlatBtn="true"]:pressed {
|
||||||
background-color: @pushbutton_flatbtn_pressed_bg;
|
background-color: @pushbutton_flatbtn_pressed_bg;
|
||||||
}
|
}
|
||||||
@ -355,11 +313,6 @@ QPushButton[FlatBtn="true"]:disabled {
|
|||||||
background-color: @pushbutton_disabled_bg;
|
background-color: @pushbutton_disabled_bg;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPushButton[FlatBtn="true"]:default {
|
|
||||||
border: 1px solid @pushbutton_default_border;
|
|
||||||
background-color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
QPushButton[SelectionBtn="true"] {
|
QPushButton[SelectionBtn="true"] {
|
||||||
padding: 4px 10px 4px 10px;
|
padding: 4px 10px 4px 10px;
|
||||||
border: none;
|
border: none;
|
||||||
@ -369,14 +322,19 @@ QPushButton[SelectionBtn="true"] {
|
|||||||
min-width: -1;
|
min-width: -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPushButton[SelectionBtn="true"]:hover {
|
QPushButton[SelectionBtn="true"]:default {
|
||||||
background-color: @pushbutton_selectionbtn_hover_bg;
|
border: 1px solid @pushbutton_default_border;
|
||||||
|
background-color: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPushButton[SelectionBtn="true"]:focus {
|
QPushButton[SelectionBtn="true"]:focus {
|
||||||
background-color: @pushbutton_selectionbtn_focus_bg;
|
background-color: @pushbutton_selectionbtn_focus_bg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QPushButton[SelectionBtn="true"]:hover {
|
||||||
|
background-color: @pushbutton_selectionbtn_hover_bg;
|
||||||
|
}
|
||||||
|
|
||||||
QPushButton[SelectionBtn="true"]:pressed {
|
QPushButton[SelectionBtn="true"]:pressed {
|
||||||
background-color: @pushbutton_selectionbtn_pressed_bg;
|
background-color: @pushbutton_selectionbtn_pressed_bg;
|
||||||
}
|
}
|
||||||
@ -386,11 +344,6 @@ QPushButton[SelectionBtn="true"]:disabled {
|
|||||||
background-color: @pushbutton_disabled_bg;
|
background-color: @pushbutton_disabled_bg;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPushButton[SelectionBtn="true"]:default {
|
|
||||||
border: 1px solid @pushbutton_default_border;
|
|
||||||
background-color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
QPushButton[TitleBtn="true"] {
|
QPushButton[TitleBtn="true"] {
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
@ -399,14 +352,19 @@ QPushButton[TitleBtn="true"] {
|
|||||||
min-width: -1;
|
min-width: -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPushButton[TitleBtn="true"]:hover {
|
QPushButton[TitleBtn="true"]:default {
|
||||||
background-color: @pushbutton_titlebtn_hover_bg;
|
border: 1px solid @pushbutton_default_border;
|
||||||
|
background-color: @pushbutton_titlebtn_bg;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPushButton[TitleBtn="true"]:focus {
|
QPushButton[TitleBtn="true"]:focus {
|
||||||
background-color: @pushbutton_titlebtn_focus_bg;
|
background-color: @pushbutton_titlebtn_focus_bg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QPushButton[TitleBtn="true"]:hover {
|
||||||
|
background-color: @pushbutton_titlebtn_hover_bg;
|
||||||
|
}
|
||||||
|
|
||||||
QPushButton[TitleBtn="true"]:pressed {
|
QPushButton[TitleBtn="true"]:pressed {
|
||||||
background-color: @pushbutton_titlebtn_pressed_bg;
|
background-color: @pushbutton_titlebtn_pressed_bg;
|
||||||
}
|
}
|
||||||
@ -416,11 +374,6 @@ QPushButton[TitleBtn="true"]:disabled {
|
|||||||
background-color: @pushbutton_disabled_bg;
|
background-color: @pushbutton_disabled_bg;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPushButton[TitleBtn="true"]:default {
|
|
||||||
border: 1px solid @pushbutton_default_border;
|
|
||||||
background-color: @pushbutton_titlebtn_bg;
|
|
||||||
}
|
|
||||||
|
|
||||||
QPushButton[DangerBtn="true"] {
|
QPushButton[DangerBtn="true"] {
|
||||||
color: @pushbutton_dangerbtn_fg;
|
color: @pushbutton_dangerbtn_fg;
|
||||||
border: none;
|
border: none;
|
||||||
@ -428,21 +381,25 @@ QPushButton[DangerBtn="true"] {
|
|||||||
min-width: -1;
|
min-width: -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPushButton[DangerBtn="true"]:hover {
|
QPushButton[DangerBtn="true"]:default {
|
||||||
background-color: @pushbutton_dangerbtn_hover_bg;
|
border: 1px solid @pushbutton_default_border;
|
||||||
|
background-color: @pushbutton_dangerbtn_bg;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPushButton[DangerBtn="true"]:focus {
|
QPushButton[DangerBtn="true"]:focus {
|
||||||
background-color: @pushbutton_dangerbtn_focus_bg;
|
background-color: @pushbutton_dangerbtn_focus_bg;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPushButton[DangerBtn="true"]:pressed {
|
QPushButton[DangerBtn="true"]:checked {
|
||||||
background-color: @pushbutton_dangerbtn_pressed_bg;
|
background-color: @pushbutton_dangerbtn_pressed_bg;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPushButton[DangerBtn="true"]:default {
|
QPushButton[DangerBtn="true"]:hover {
|
||||||
border: 1px solid @pushbutton_default_border;
|
background-color: @pushbutton_dangerbtn_hover_bg;
|
||||||
background-color: @pushbutton_dangerbtn_bg;
|
}
|
||||||
|
|
||||||
|
QPushButton[DangerBtn="true"]:pressed {
|
||||||
|
background-color: @pushbutton_dangerbtn_pressed_bg;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPushButton[DangerBtn="true"]:disabled {
|
QPushButton[DangerBtn="true"]:disabled {
|
||||||
@ -459,28 +416,28 @@ QPushButton[ToolBoxActiveBtn="true"] {
|
|||||||
min-width: -1;
|
min-width: -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPushButton[ToolBoxActiveBtn="true"]:focus {
|
QPushButton[ToolBoxActiveBtn="true"]:default {
|
||||||
background-color: @pushbutton_toolboxbtn_active_focus_bg;
|
border: 1px solid @pushbutton_default_border;
|
||||||
|
background-color: @pushbutton_toolboxbtn_active_bg;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPushButton[ToolBoxActiveBtn="true"]:hover {
|
QPushButton[ToolBoxActiveBtn="true"]:focus {
|
||||||
background-color: @pushbutton_toolboxbtn_active_hover_bg;
|
background-color: @pushbutton_toolboxbtn_active_focus_bg;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPushButton[ToolBoxActiveBtn="true"]:pressed {
|
QPushButton[ToolBoxActiveBtn="true"]:pressed {
|
||||||
background-color: @pushbutton_toolboxbtn_active_pressed_bg;
|
background-color: @pushbutton_toolboxbtn_active_pressed_bg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QPushButton[ToolBoxActiveBtn="true"]:hover {
|
||||||
|
background-color: @pushbutton_toolboxbtn_active_hover_bg;
|
||||||
|
}
|
||||||
|
|
||||||
QPushButton[ToolBoxActiveBtn="true"]:disabled {
|
QPushButton[ToolBoxActiveBtn="true"]:disabled {
|
||||||
color: @pushbutton_disabled_fg;
|
color: @pushbutton_disabled_fg;
|
||||||
background-color: @pushbutton_disabled_bg;
|
background-color: @pushbutton_disabled_bg;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPushButton[ToolBoxActiveBtn="true"]:default {
|
|
||||||
border: 1px solid @pushbutton_default_border;
|
|
||||||
background-color: @pushbutton_toolboxbtn_active_bg;
|
|
||||||
}
|
|
||||||
|
|
||||||
QPushButton[AvatarBtn="true"] {
|
QPushButton[AvatarBtn="true"] {
|
||||||
padding: 2px 4px 2px 4px;
|
padding: 2px 4px 2px 4px;
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
@ -489,14 +446,19 @@ QPushButton[AvatarBtn="true"] {
|
|||||||
min-width: -1;
|
min-width: -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPushButton[AvatarBtn="true"]:hover {
|
|
||||||
background-color: @pushbutton_avatarbtn_hover_bg;
|
|
||||||
}
|
|
||||||
|
|
||||||
QPushButton[AvatarBtn="true"]:focus {
|
QPushButton[AvatarBtn="true"]:focus {
|
||||||
background-color: @pushbutton_avatarbtn_focus_bg;;
|
background-color: @pushbutton_avatarbtn_focus_bg;;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QPushButton[AvatarBtn="true"]:default {
|
||||||
|
border: 1px solid @pushbutton_default_border;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPushButton[AvatarBtn="true"]:hover {
|
||||||
|
background-color: @pushbutton_avatarbtn_hover_bg;
|
||||||
|
}
|
||||||
|
|
||||||
QPushButton[AvatarBtn="true"]:pressed {
|
QPushButton[AvatarBtn="true"]:pressed {
|
||||||
background-color: @pushbutton_avatarbtn_pressed_bg;
|
background-color: @pushbutton_avatarbtn_pressed_bg;
|
||||||
}
|
}
|
||||||
@ -506,9 +468,51 @@ QPushButton[AvatarBtn="true"]:disabled {
|
|||||||
background-color: @pushbutton_disabled_bg;
|
background-color: @pushbutton_disabled_bg;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPushButton[AvatarBtn="true"]:default {
|
QPushButton {
|
||||||
|
color: @pushbutton_fg;
|
||||||
|
background: @pushbutton_bg;
|
||||||
|
border: 1px solid @pushbutton_border;
|
||||||
|
padding: 3px;
|
||||||
|
min-width: 80px;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPushButton:focus {
|
||||||
|
background-color: @pushbutton_focus_bg;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPushButton:checked {
|
||||||
|
background-color: @pushbutton_checked_bg;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPushButton:checked:hover {
|
||||||
|
background-color: @pushbutton_hover_bg;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPushButton:flat {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPushButton:default {
|
||||||
border: 1px solid @pushbutton_default_border;
|
border: 1px solid @pushbutton_default_border;
|
||||||
background-color: transparent;
|
}
|
||||||
|
|
||||||
|
QPushButton:hover {
|
||||||
|
background-color: @pushbutton_hover_bg;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPushButton:pressed {
|
||||||
|
background-color: @pushbutton_pressed_bg;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPushButton:disabled {
|
||||||
|
color: @pushbutton_disabled_fg;
|
||||||
|
background-color: @pushbutton_disabled_bg;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPushButton::menu-indicator {
|
||||||
|
image: url(arrow_dropdown.svg);
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
VButtonMenuItem {
|
VButtonMenuItem {
|
||||||
@ -544,11 +548,11 @@ VButtonMenuItem[Heading6="true"] {
|
|||||||
font-size: 14pt;
|
font-size: 14pt;
|
||||||
}
|
}
|
||||||
|
|
||||||
VButtonMenuItem:hover {
|
VButtonMenuItem:focus {
|
||||||
background-color: @menubar_item_selected_bg;
|
background-color: @menubar_item_selected_bg;
|
||||||
}
|
}
|
||||||
|
|
||||||
VButtonMenuItem:focus {
|
VButtonMenuItem:hover {
|
||||||
background-color: @menubar_item_selected_bg;
|
background-color: @menubar_item_selected_bg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,6 +149,9 @@ enable_compact_mode=true
|
|||||||
; Whether enable tools dock widget
|
; Whether enable tools dock widget
|
||||||
tools_dock_checked=true
|
tools_dock_checked=true
|
||||||
|
|
||||||
|
; Whether enable search dock widget
|
||||||
|
search_dock_checked=false
|
||||||
|
|
||||||
; Whether show menu bar
|
; Whether show menu bar
|
||||||
menu_bar_checked=true
|
menu_bar_checked=true
|
||||||
|
|
||||||
@ -201,6 +204,10 @@ single_click_close_previous_tab=true
|
|||||||
; Whether enable auto wildcard match in simple search like list and tree widgets
|
; Whether enable auto wildcard match in simple search like list and tree widgets
|
||||||
enable_wildcard_in_simple_search=true
|
enable_wildcard_in_simple_search=true
|
||||||
|
|
||||||
|
; Search options
|
||||||
|
; scope,object,target,engine,option,pattern
|
||||||
|
search_options=4,2,7,0,0,""
|
||||||
|
|
||||||
[export]
|
[export]
|
||||||
; Path of the wkhtmltopdf tool
|
; Path of the wkhtmltopdf tool
|
||||||
wkhtmltopdf=wkhtmltopdf
|
wkhtmltopdf=wkhtmltopdf
|
||||||
@ -279,6 +286,8 @@ Find=Ctrl+F
|
|||||||
FindNext=F3
|
FindNext=F3
|
||||||
; Find previous occurence
|
; Find previous occurence
|
||||||
FindPrevious=Shift+F3
|
FindPrevious=Shift+F3
|
||||||
|
; Advanced find
|
||||||
|
AdvancedFind=Ctrl+Alt+F
|
||||||
; Recover last closed file
|
; Recover last closed file
|
||||||
LastClosedFile=Ctrl+Shift+T
|
LastClosedFile=Ctrl+Shift+T
|
||||||
; Activate next tab
|
; Activate next tab
|
||||||
@ -311,6 +320,8 @@ OnePanelView=P
|
|||||||
DiscardAndRead=Q
|
DiscardAndRead=Q
|
||||||
; Toggle Tools dock widget
|
; Toggle Tools dock widget
|
||||||
ToolsDock=T
|
ToolsDock=T
|
||||||
|
; Toggle Search dock widget
|
||||||
|
SearchDock=C
|
||||||
; Close current note
|
; Close current note
|
||||||
CloseNote=X
|
CloseNote=X
|
||||||
; Show shortcuts help document
|
; Show shortcuts help document
|
||||||
|
14
src/src.pro
14
src/src.pro
@ -113,7 +113,11 @@ SOURCES += main.cpp\
|
|||||||
vstyleditemdelegate.cpp \
|
vstyleditemdelegate.cpp \
|
||||||
vtreewidget.cpp \
|
vtreewidget.cpp \
|
||||||
dialog/vexportdialog.cpp \
|
dialog/vexportdialog.cpp \
|
||||||
vexporter.cpp
|
vexporter.cpp \
|
||||||
|
vsearcher.cpp \
|
||||||
|
vsearch.cpp \
|
||||||
|
vsearchresulttree.cpp \
|
||||||
|
vsearchengine.cpp
|
||||||
|
|
||||||
HEADERS += vmainwindow.h \
|
HEADERS += vmainwindow.h \
|
||||||
vdirectorytree.h \
|
vdirectorytree.h \
|
||||||
@ -214,7 +218,13 @@ HEADERS += vmainwindow.h \
|
|||||||
vtreewidget.h \
|
vtreewidget.h \
|
||||||
dialog/vexportdialog.h \
|
dialog/vexportdialog.h \
|
||||||
vexporter.h \
|
vexporter.h \
|
||||||
vwordcountinfo.h
|
vwordcountinfo.h \
|
||||||
|
vsearcher.h \
|
||||||
|
vsearch.h \
|
||||||
|
vsearchresulttree.h \
|
||||||
|
isearchengine.h \
|
||||||
|
vsearchconfig.h \
|
||||||
|
vsearchengine.h
|
||||||
|
|
||||||
RESOURCES += \
|
RESOURCES += \
|
||||||
vnote.qrc \
|
vnote.qrc \
|
||||||
|
@ -522,13 +522,18 @@ bool VUtils::isImageURLText(const QString &p_url)
|
|||||||
|
|
||||||
qreal VUtils::calculateScaleFactor()
|
qreal VUtils::calculateScaleFactor()
|
||||||
{
|
{
|
||||||
// const qreal refHeight = 1152;
|
static qreal factor = -1;
|
||||||
// const qreal refWidth = 2048;
|
|
||||||
const qreal refDpi = 96;
|
|
||||||
|
|
||||||
|
if (factor < 0) {
|
||||||
|
const qreal refDpi = 96;
|
||||||
qreal dpi = QGuiApplication::primaryScreen()->logicalDotsPerInch();
|
qreal dpi = QGuiApplication::primaryScreen()->logicalDotsPerInch();
|
||||||
qreal factor = dpi / refDpi;
|
factor = dpi / refDpi;
|
||||||
return factor < 1 ? 1 : factor;
|
if (factor < 1) {
|
||||||
|
factor = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return factor;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VUtils::realEqual(qreal p_a, qreal p_b)
|
bool VUtils::realEqual(qreal p_a, qreal p_b)
|
||||||
|
@ -104,8 +104,6 @@ void VConfigManager::initialize()
|
|||||||
curRenderBackgroundColor = getConfigFromSettings("global",
|
curRenderBackgroundColor = getConfigFromSettings("global",
|
||||||
"current_render_background_color").toString();
|
"current_render_background_color").toString();
|
||||||
|
|
||||||
m_toolsDockChecked = getConfigFromSettings("global", "tools_dock_checked").toBool();
|
|
||||||
|
|
||||||
m_findCaseSensitive = getConfigFromSettings("global",
|
m_findCaseSensitive = getConfigFromSettings("global",
|
||||||
"find_case_sensitive").toBool();
|
"find_case_sensitive").toBool();
|
||||||
m_findWholeWordOnly = getConfigFromSettings("global",
|
m_findWholeWordOnly = getConfigFromSettings("global",
|
||||||
@ -498,11 +496,9 @@ QString VConfigManager::fetchDirConfigFilePath(const QString &p_path)
|
|||||||
if (!dir.rename(c_obsoleteDirConfigFile, c_dirConfigFile)) {
|
if (!dir.rename(c_obsoleteDirConfigFile, c_dirConfigFile)) {
|
||||||
fileName = c_obsoleteDirConfigFile;
|
fileName = c_obsoleteDirConfigFile;
|
||||||
}
|
}
|
||||||
qDebug() << "rename old directory config file:" << fileName;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString filePath = QDir::cleanPath(dir.filePath(fileName));
|
QString filePath = QDir::cleanPath(dir.filePath(fileName));
|
||||||
qDebug() << "use directory config file:" << filePath;
|
|
||||||
return filePath;
|
return filePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1473,6 +1469,7 @@ void VConfigManager::resetConfigurations()
|
|||||||
void VConfigManager::resetLayoutConfigurations()
|
void VConfigManager::resetLayoutConfigurations()
|
||||||
{
|
{
|
||||||
resetDefaultConfig("global", "tools_dock_checked");
|
resetDefaultConfig("global", "tools_dock_checked");
|
||||||
|
resetDefaultConfig("global", "search_dock_checked");
|
||||||
resetDefaultConfig("global", "menu_bar_checked");
|
resetDefaultConfig("global", "menu_bar_checked");
|
||||||
resetDefaultConfig("global", "enable_compact_mode");
|
resetDefaultConfig("global", "enable_compact_mode");
|
||||||
|
|
||||||
|
@ -184,6 +184,9 @@ public:
|
|||||||
bool getToolsDockChecked() const;
|
bool getToolsDockChecked() const;
|
||||||
void setToolsDockChecked(bool p_checked);
|
void setToolsDockChecked(bool p_checked);
|
||||||
|
|
||||||
|
bool getSearchDockChecked() const;
|
||||||
|
void setSearchDockChecked(bool p_checked);
|
||||||
|
|
||||||
const QByteArray &getMainWindowGeometry() const;
|
const QByteArray &getMainWindowGeometry() const;
|
||||||
void setMainWindowGeometry(const QByteArray &p_geometry);
|
void setMainWindowGeometry(const QByteArray &p_geometry);
|
||||||
|
|
||||||
@ -466,6 +469,9 @@ public:
|
|||||||
QStringList getCustomExport() const;
|
QStringList getCustomExport() const;
|
||||||
void setCustomExport(const QStringList &p_exp);
|
void setCustomExport(const QStringList &p_exp);
|
||||||
|
|
||||||
|
QStringList getSearchOptions() const;
|
||||||
|
void setSearchOptions(const QStringList &p_opts);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Look up a config from user and default settings.
|
// Look up a config from user and default settings.
|
||||||
QVariant getConfigFromSettings(const QString §ion, const QString &key) const;
|
QVariant getConfigFromSettings(const QString §ion, const QString &key) const;
|
||||||
@ -605,8 +611,6 @@ private:
|
|||||||
|
|
||||||
QString curRenderBackgroundColor;
|
QString curRenderBackgroundColor;
|
||||||
|
|
||||||
bool m_toolsDockChecked;
|
|
||||||
|
|
||||||
QByteArray m_mainWindowGeometry;
|
QByteArray m_mainWindowGeometry;
|
||||||
QByteArray m_mainWindowState;
|
QByteArray m_mainWindowState;
|
||||||
QByteArray m_mainSplitterState;
|
QByteArray m_mainSplitterState;
|
||||||
@ -1153,14 +1157,26 @@ inline void VConfigManager::setCurRenderBackgroundColor(const QString &colorName
|
|||||||
|
|
||||||
inline bool VConfigManager::getToolsDockChecked() const
|
inline bool VConfigManager::getToolsDockChecked() const
|
||||||
{
|
{
|
||||||
return m_toolsDockChecked;
|
return getConfigFromSettings("global", "tools_dock_checked").toBool();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void VConfigManager::setToolsDockChecked(bool p_checked)
|
inline void VConfigManager::setToolsDockChecked(bool p_checked)
|
||||||
{
|
{
|
||||||
m_toolsDockChecked = p_checked;
|
setConfigToSettings("global",
|
||||||
setConfigToSettings("global", "tools_dock_checked",
|
"tools_dock_checked",
|
||||||
m_toolsDockChecked);
|
p_checked);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool VConfigManager::getSearchDockChecked() const
|
||||||
|
{
|
||||||
|
return getConfigFromSettings("global", "search_dock_checked").toBool();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void VConfigManager::setSearchDockChecked(bool p_checked)
|
||||||
|
{
|
||||||
|
setConfigToSettings("global",
|
||||||
|
"search_dock_checked",
|
||||||
|
p_checked);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const QByteArray& VConfigManager::getMainWindowGeometry() const
|
inline const QByteArray& VConfigManager::getMainWindowGeometry() const
|
||||||
@ -2146,4 +2162,15 @@ inline void VConfigManager::setCustomExport(const QStringList &p_exp)
|
|||||||
{
|
{
|
||||||
setConfigToSettings("export", "custom_export", p_exp);
|
setConfigToSettings("export", "custom_export", p_exp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline QStringList VConfigManager::getSearchOptions() const
|
||||||
|
{
|
||||||
|
return getConfigFromSettings("global",
|
||||||
|
"search_options").toStringList();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void VConfigManager::setSearchOptions(const QStringList &p_opts)
|
||||||
|
{
|
||||||
|
setConfigToSettings("global", "search_options", p_opts);
|
||||||
|
}
|
||||||
#endif // VCONFIGMANAGER_H
|
#endif // VCONFIGMANAGER_H
|
||||||
|
@ -191,12 +191,14 @@ void VDirectoryTree::setNotebook(VNotebook *p_notebook)
|
|||||||
|
|
||||||
void VDirectoryTree::fillTreeItem(QTreeWidgetItem *p_item, VDirectory *p_directory)
|
void VDirectoryTree::fillTreeItem(QTreeWidgetItem *p_item, VDirectory *p_directory)
|
||||||
{
|
{
|
||||||
|
static QIcon itemIcon = VIconUtils::treeViewIcon(":/resources/icons/dir_item.svg");
|
||||||
|
|
||||||
int col = 0;
|
int col = 0;
|
||||||
QString name = p_directory->getName();
|
QString name = p_directory->getName();
|
||||||
p_item->setText(col, name);
|
p_item->setText(col, name);
|
||||||
p_item->setToolTip(col, name);
|
p_item->setToolTip(col, name);
|
||||||
p_item->setData(col, Qt::UserRole, QVariant::fromValue(p_directory));
|
p_item->setData(col, Qt::UserRole, QVariant::fromValue(p_directory));
|
||||||
p_item->setIcon(col, VIconUtils::treeViewIcon(":/resources/icons/dir_item.svg"));
|
p_item->setIcon(col, itemIcon);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VDirectoryTree::updateDirectoryTree()
|
void VDirectoryTree::updateDirectoryTree()
|
||||||
|
@ -188,6 +188,7 @@ void VEdit::insertLink()
|
|||||||
"",
|
"",
|
||||||
linkText,
|
linkText,
|
||||||
linkUrl,
|
linkUrl,
|
||||||
|
false,
|
||||||
this);
|
this);
|
||||||
if (dialog.exec() == QDialog::Accepted) {
|
if (dialog.exec() == QDialog::Accepted) {
|
||||||
linkText = dialog.getLinkText();
|
linkText = dialog.getLinkText();
|
||||||
|
@ -570,6 +570,20 @@ VEditTab *VEditArea::getTab(int p_winIdx, int p_tabIdx) const
|
|||||||
return win->getTab(p_tabIdx);
|
return win->getTab(p_tabIdx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VEditTab *VEditArea::getTab(const VFile *p_file) const
|
||||||
|
{
|
||||||
|
int nrWin = splitter->count();
|
||||||
|
for (int winIdx = 0; winIdx < nrWin; ++winIdx) {
|
||||||
|
VEditWindow *win = getWindow(winIdx);
|
||||||
|
int tabIdx = win->findTabByFile(p_file);
|
||||||
|
if (tabIdx != -1) {
|
||||||
|
return win->getTab(tabIdx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
QVector<VEditTabInfo> VEditArea::getAllTabsInfo() const
|
QVector<VEditTabInfo> VEditArea::getAllTabsInfo() const
|
||||||
{
|
{
|
||||||
QVector<VEditTabInfo> tabs;
|
QVector<VEditTabInfo> tabs;
|
||||||
|
@ -44,6 +44,9 @@ public:
|
|||||||
// Return the @p_tabIdx tab in the @p_winIdx window.
|
// Return the @p_tabIdx tab in the @p_winIdx window.
|
||||||
VEditTab *getTab(int p_winIdx, int p_tabIdx) const;
|
VEditTab *getTab(int p_winIdx, int p_tabIdx) const;
|
||||||
|
|
||||||
|
// Return the tab for @p_file file.
|
||||||
|
VEditTab *getTab(const VFile *p_file) const;
|
||||||
|
|
||||||
// Return VEditTabInfo of all edit tabs.
|
// Return VEditTabInfo of all edit tabs.
|
||||||
QVector<VEditTabInfo> getAllTabsInfo() const;
|
QVector<VEditTabInfo> getAllTabsInfo() const;
|
||||||
|
|
||||||
|
@ -38,6 +38,7 @@
|
|||||||
#include "dialog/vtipsdialog.h"
|
#include "dialog/vtipsdialog.h"
|
||||||
#include "vcart.h"
|
#include "vcart.h"
|
||||||
#include "dialog/vexportdialog.h"
|
#include "dialog/vexportdialog.h"
|
||||||
|
#include "vsearcher.h"
|
||||||
|
|
||||||
extern VConfigManager *g_config;
|
extern VConfigManager *g_config;
|
||||||
|
|
||||||
@ -148,6 +149,7 @@ void VMainWindow::registerCaptainAndNavigationTargets()
|
|||||||
m_captain->registerNavigationTarget(m_toolBox);
|
m_captain->registerNavigationTarget(m_toolBox);
|
||||||
m_captain->registerNavigationTarget(outline);
|
m_captain->registerNavigationTarget(outline);
|
||||||
m_captain->registerNavigationTarget(m_snippetList);
|
m_captain->registerNavigationTarget(m_snippetList);
|
||||||
|
m_captain->registerNavigationTarget(m_searcher);
|
||||||
|
|
||||||
// Register Captain mode targets.
|
// Register Captain mode targets.
|
||||||
m_captain->registerCaptainTarget(tr("AttachmentList"),
|
m_captain->registerCaptainTarget(tr("AttachmentList"),
|
||||||
@ -174,6 +176,10 @@ void VMainWindow::registerCaptainAndNavigationTargets()
|
|||||||
g_config->getCaptainShortcutKeySequence("ToolsDock"),
|
g_config->getCaptainShortcutKeySequence("ToolsDock"),
|
||||||
this,
|
this,
|
||||||
toggleToolsDockByCaptain);
|
toggleToolsDockByCaptain);
|
||||||
|
m_captain->registerCaptainTarget(tr("SearchDock"),
|
||||||
|
g_config->getCaptainShortcutKeySequence("SearchDock"),
|
||||||
|
this,
|
||||||
|
toggleSearchDockByCaptain);
|
||||||
m_captain->registerCaptainTarget(tr("CloseNote"),
|
m_captain->registerCaptainTarget(tr("CloseNote"),
|
||||||
g_config->getCaptainShortcutKeySequence("CloseNote"),
|
g_config->getCaptainShortcutKeySequence("CloseNote"),
|
||||||
this,
|
this,
|
||||||
@ -1073,6 +1079,17 @@ void VMainWindow::initEditMenu()
|
|||||||
connect(m_findReplaceAct, &QAction::triggered,
|
connect(m_findReplaceAct, &QAction::triggered,
|
||||||
this, &VMainWindow::openFindDialog);
|
this, &VMainWindow::openFindDialog);
|
||||||
|
|
||||||
|
QAction *advFindAct = new QAction(tr("Advanced Find"), this);
|
||||||
|
advFindAct->setToolTip(tr("Advanced find within VNote"));
|
||||||
|
keySeq = g_config->getShortcutKeySequence("AdvancedFind");
|
||||||
|
qDebug() << "set AdvancedFind shortcut to" << keySeq;
|
||||||
|
advFindAct->setShortcut(QKeySequence(keySeq));
|
||||||
|
connect(advFindAct, &QAction::triggered,
|
||||||
|
this, [this]() {
|
||||||
|
m_searchDock->setVisible(true);
|
||||||
|
m_searcher->focusToSearch();
|
||||||
|
});
|
||||||
|
|
||||||
m_findNextAct = new QAction(tr("Find Next"), this);
|
m_findNextAct = new QAction(tr("Find Next"), this);
|
||||||
m_findNextAct->setToolTip(tr("Find next occurence"));
|
m_findNextAct->setToolTip(tr("Find next occurence"));
|
||||||
keySeq = g_config->getShortcutKeySequence("FindNext");
|
keySeq = g_config->getShortcutKeySequence("FindNext");
|
||||||
@ -1188,6 +1205,8 @@ void VMainWindow::initEditMenu()
|
|||||||
QMenu *findReplaceMenu = editMenu->addMenu(tr("Find/Replace"));
|
QMenu *findReplaceMenu = editMenu->addMenu(tr("Find/Replace"));
|
||||||
findReplaceMenu->setToolTipsVisible(true);
|
findReplaceMenu->setToolTipsVisible(true);
|
||||||
findReplaceMenu->addAction(m_findReplaceAct);
|
findReplaceMenu->addAction(m_findReplaceAct);
|
||||||
|
findReplaceMenu->addAction(advFindAct);
|
||||||
|
findReplaceMenu->addSeparator();
|
||||||
findReplaceMenu->addAction(m_findNextAct);
|
findReplaceMenu->addAction(m_findNextAct);
|
||||||
findReplaceMenu->addAction(m_findPreviousAct);
|
findReplaceMenu->addAction(m_findPreviousAct);
|
||||||
findReplaceMenu->addAction(m_replaceAct);
|
findReplaceMenu->addAction(m_replaceAct);
|
||||||
@ -1268,9 +1287,22 @@ void VMainWindow::initEditMenu()
|
|||||||
|
|
||||||
void VMainWindow::initDockWindows()
|
void VMainWindow::initDockWindows()
|
||||||
{
|
{
|
||||||
toolDock = new QDockWidget(tr("Tools"), this);
|
setTabPosition(Qt::LeftDockWidgetArea, QTabWidget::West);
|
||||||
toolDock->setObjectName("ToolsDock");
|
setTabPosition(Qt::RightDockWidgetArea, QTabWidget::East);
|
||||||
toolDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
|
setTabPosition(Qt::TopDockWidgetArea, QTabWidget::North);
|
||||||
|
setTabPosition(Qt::BottomDockWidgetArea, QTabWidget::South);
|
||||||
|
|
||||||
|
setDockNestingEnabled(true);
|
||||||
|
|
||||||
|
initToolsDock();
|
||||||
|
initSearchDock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VMainWindow::initToolsDock()
|
||||||
|
{
|
||||||
|
m_toolDock = new QDockWidget(tr("Tools"), this);
|
||||||
|
m_toolDock->setObjectName("ToolsDock");
|
||||||
|
m_toolDock->setAllowedAreas(Qt::AllDockWidgetAreas);
|
||||||
|
|
||||||
// Outline tree.
|
// Outline tree.
|
||||||
outline = new VOutline(this);
|
outline = new VOutline(this);
|
||||||
@ -1298,16 +1330,35 @@ void VMainWindow::initDockWindows()
|
|||||||
":/resources/icons/cart.svg",
|
":/resources/icons/cart.svg",
|
||||||
tr("Cart"));
|
tr("Cart"));
|
||||||
|
|
||||||
toolDock->setWidget(m_toolBox);
|
m_toolDock->setWidget(m_toolBox);
|
||||||
addDockWidget(Qt::RightDockWidgetArea, toolDock);
|
addDockWidget(Qt::RightDockWidgetArea, m_toolDock);
|
||||||
|
|
||||||
QAction *toggleAct = toolDock->toggleViewAction();
|
QAction *toggleAct = m_toolDock->toggleViewAction();
|
||||||
toggleAct->setToolTip(tr("Toggle the tools dock widget"));
|
toggleAct->setToolTip(tr("Toggle the tools dock widget"));
|
||||||
VUtils::fixTextWithCaptainShortcut(toggleAct, "ToolsDock");
|
VUtils::fixTextWithCaptainShortcut(toggleAct, "ToolsDock");
|
||||||
|
|
||||||
m_viewMenu->addAction(toggleAct);
|
m_viewMenu->addAction(toggleAct);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VMainWindow::initSearchDock()
|
||||||
|
{
|
||||||
|
m_searchDock = new QDockWidget(tr("Search"), this);
|
||||||
|
m_searchDock->setObjectName("SearchDock");
|
||||||
|
m_searchDock->setAllowedAreas(Qt::AllDockWidgetAreas);
|
||||||
|
|
||||||
|
m_searcher = new VSearcher(this);
|
||||||
|
|
||||||
|
m_searchDock->setWidget(m_searcher);
|
||||||
|
|
||||||
|
addDockWidget(Qt::RightDockWidgetArea, m_searchDock);
|
||||||
|
|
||||||
|
QAction *toggleAct = m_searchDock->toggleViewAction();
|
||||||
|
toggleAct->setToolTip(tr("Toggle the search dock widget"));
|
||||||
|
VUtils::fixTextWithCaptainShortcut(toggleAct, "SearchDock");
|
||||||
|
|
||||||
|
m_viewMenu->addAction(toggleAct);
|
||||||
|
}
|
||||||
|
|
||||||
void VMainWindow::importNoteFromFile()
|
void VMainWindow::importNoteFromFile()
|
||||||
{
|
{
|
||||||
static QString lastPath = QDir::homePath();
|
static QString lastPath = QDir::homePath();
|
||||||
@ -2162,7 +2213,8 @@ void VMainWindow::saveStateAndGeometry()
|
|||||||
{
|
{
|
||||||
g_config->setMainWindowGeometry(saveGeometry());
|
g_config->setMainWindowGeometry(saveGeometry());
|
||||||
g_config->setMainWindowState(saveState());
|
g_config->setMainWindowState(saveState());
|
||||||
g_config->setToolsDockChecked(toolDock->isVisible());
|
g_config->setToolsDockChecked(m_toolDock->isVisible());
|
||||||
|
g_config->setSearchDockChecked(m_searchDock->isVisible());
|
||||||
|
|
||||||
if (m_panelViewState == PanelViewState::CompactMode) {
|
if (m_panelViewState == PanelViewState::CompactMode) {
|
||||||
g_config->setNaviSplitterState(m_naviSplitter->saveState());
|
g_config->setNaviSplitterState(m_naviSplitter->saveState());
|
||||||
@ -2181,11 +2233,14 @@ void VMainWindow::restoreStateAndGeometry()
|
|||||||
if (!geometry.isEmpty()) {
|
if (!geometry.isEmpty()) {
|
||||||
restoreGeometry(geometry);
|
restoreGeometry(geometry);
|
||||||
}
|
}
|
||||||
|
|
||||||
const QByteArray &state = g_config->getMainWindowState();
|
const QByteArray &state = g_config->getMainWindowState();
|
||||||
if (!state.isEmpty()) {
|
if (!state.isEmpty()) {
|
||||||
restoreState(state);
|
restoreState(state);
|
||||||
}
|
}
|
||||||
toolDock->setVisible(g_config->getToolsDockChecked());
|
|
||||||
|
m_toolDock->setVisible(g_config->getToolsDockChecked());
|
||||||
|
m_searchDock->setVisible(g_config->getSearchDockChecked());
|
||||||
|
|
||||||
const QByteArray &splitterState = g_config->getMainSplitterState();
|
const QByteArray &splitterState = g_config->getMainSplitterState();
|
||||||
if (!splitterState.isEmpty()) {
|
if (!splitterState.isEmpty()) {
|
||||||
@ -2260,6 +2315,32 @@ bool VMainWindow::locateFile(VFile *p_file)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool VMainWindow::locateDirectory(VDirectory *p_directory)
|
||||||
|
{
|
||||||
|
bool ret = false;
|
||||||
|
if (!p_directory) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
VNotebook *notebook = p_directory->getNotebook();
|
||||||
|
if (notebookSelector->locateNotebook(notebook)) {
|
||||||
|
while (directoryTree->currentNotebook() != notebook) {
|
||||||
|
QCoreApplication::sendPostedEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = directoryTree->locateDirectory(p_directory);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open the directory and file panels after location.
|
||||||
|
if (m_panelViewState == PanelViewState::CompactMode) {
|
||||||
|
compactModeView();
|
||||||
|
} else {
|
||||||
|
twoPanelView();
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
void VMainWindow::handleFindDialogTextChanged(const QString &p_text, uint /* p_options */)
|
void VMainWindow::handleFindDialogTextChanged(const QString &p_text, uint /* p_options */)
|
||||||
{
|
{
|
||||||
bool enabled = true;
|
bool enabled = true;
|
||||||
@ -2659,7 +2740,21 @@ bool VMainWindow::toggleToolsDockByCaptain(void *p_target, void *p_data)
|
|||||||
{
|
{
|
||||||
Q_UNUSED(p_data);
|
Q_UNUSED(p_data);
|
||||||
VMainWindow *obj = static_cast<VMainWindow *>(p_target);
|
VMainWindow *obj = static_cast<VMainWindow *>(p_target);
|
||||||
obj->toolDock->setVisible(!obj->toolDock->isVisible());
|
obj->m_toolDock->setVisible(!obj->m_toolDock->isVisible());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VMainWindow::toggleSearchDockByCaptain(void *p_target, void *p_data)
|
||||||
|
{
|
||||||
|
Q_UNUSED(p_data);
|
||||||
|
VMainWindow *obj = static_cast<VMainWindow *>(p_target);
|
||||||
|
bool visible = obj->m_searchDock->isVisible();
|
||||||
|
obj->m_searchDock->setVisible(!visible);
|
||||||
|
if (!visible) {
|
||||||
|
obj->m_searcher->focusToSearch();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,6 +39,7 @@ class VButtonWithWidget;
|
|||||||
class VAttachmentList;
|
class VAttachmentList;
|
||||||
class VSnippetList;
|
class VSnippetList;
|
||||||
class VCart;
|
class VCart;
|
||||||
|
class VSearcher;
|
||||||
class QPrinter;
|
class QPrinter;
|
||||||
|
|
||||||
enum class PanelViewState
|
enum class PanelViewState
|
||||||
@ -60,6 +61,9 @@ public:
|
|||||||
// Returns true if the location succeeds.
|
// Returns true if the location succeeds.
|
||||||
bool locateFile(VFile *p_file);
|
bool locateFile(VFile *p_file);
|
||||||
|
|
||||||
|
// Returns true if the location succeeds.
|
||||||
|
bool locateDirectory(VDirectory *p_directory);
|
||||||
|
|
||||||
VFileList *getFileList() const;
|
VFileList *getFileList() const;
|
||||||
|
|
||||||
VEditArea *getEditArea() const;
|
VEditArea *getEditArea() const;
|
||||||
@ -68,6 +72,10 @@ public:
|
|||||||
|
|
||||||
VCart *getCart() const;
|
VCart *getCart() const;
|
||||||
|
|
||||||
|
VDirectoryTree *getDirectoryTree() const;
|
||||||
|
|
||||||
|
VNotebookSelector *getNotebookSelector() const;
|
||||||
|
|
||||||
// View and edit the information of @p_file, which is an orphan file.
|
// View and edit the information of @p_file, which is an orphan file.
|
||||||
void editOrphanFileInfo(VFile *p_file);
|
void editOrphanFileInfo(VFile *p_file);
|
||||||
|
|
||||||
@ -205,6 +213,10 @@ private:
|
|||||||
|
|
||||||
void initDockWindows();
|
void initDockWindows();
|
||||||
|
|
||||||
|
void initToolsDock();
|
||||||
|
|
||||||
|
void initSearchDock();
|
||||||
|
|
||||||
void initRenderBackgroundMenu(QMenu *menu);
|
void initRenderBackgroundMenu(QMenu *menu);
|
||||||
|
|
||||||
void initRenderStyleMenu(QMenu *p_menu);
|
void initRenderStyleMenu(QMenu *p_menu);
|
||||||
@ -280,6 +292,8 @@ private:
|
|||||||
|
|
||||||
static bool toggleToolsDockByCaptain(void *p_target, void *p_data);
|
static bool toggleToolsDockByCaptain(void *p_target, void *p_data);
|
||||||
|
|
||||||
|
static bool toggleSearchDockByCaptain(void *p_target, void *p_data);
|
||||||
|
|
||||||
static bool closeFileByCaptain(void *p_target, void *p_data);
|
static bool closeFileByCaptain(void *p_target, void *p_data);
|
||||||
|
|
||||||
static bool shortcutsHelpByCaptain(void *p_target, void *p_data);
|
static bool shortcutsHelpByCaptain(void *p_target, void *p_data);
|
||||||
@ -311,7 +325,9 @@ private:
|
|||||||
|
|
||||||
VEditArea *editArea;
|
VEditArea *editArea;
|
||||||
|
|
||||||
QDockWidget *toolDock;
|
QDockWidget *m_toolDock;
|
||||||
|
|
||||||
|
QDockWidget *m_searchDock;
|
||||||
|
|
||||||
// Tool box in the dock widget.
|
// Tool box in the dock widget.
|
||||||
VToolBox *m_toolBox;
|
VToolBox *m_toolBox;
|
||||||
@ -324,6 +340,9 @@ private:
|
|||||||
// View and manage cart.
|
// View and manage cart.
|
||||||
VCart *m_cart;
|
VCart *m_cart;
|
||||||
|
|
||||||
|
// Advanced search.
|
||||||
|
VSearcher *m_searcher;
|
||||||
|
|
||||||
VFindReplaceDialog *m_findReplaceDialog;
|
VFindReplaceDialog *m_findReplaceDialog;
|
||||||
|
|
||||||
VVimCmdLineEdit *m_vimCmd;
|
VVimCmdLineEdit *m_vimCmd;
|
||||||
@ -453,4 +472,13 @@ inline VCart *VMainWindow::getCart() const
|
|||||||
return m_cart;
|
return m_cart;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline VDirectoryTree *VMainWindow::getDirectoryTree() const
|
||||||
|
{
|
||||||
|
return directoryTree;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline VNotebookSelector *VMainWindow::getNotebookSelector() const
|
||||||
|
{
|
||||||
|
return notebookSelector;
|
||||||
|
}
|
||||||
#endif // VMAINWINDOW_H
|
#endif // VMAINWINDOW_H
|
||||||
|
@ -95,6 +95,8 @@ VMdEditor::VMdEditor(VFile *p_file,
|
|||||||
connect(this, &VTextEdit::cursorPositionChanged,
|
connect(this, &VTextEdit::cursorPositionChanged,
|
||||||
this, &VMdEditor::updateCurrentHeader);
|
this, &VMdEditor::updateCurrentHeader);
|
||||||
|
|
||||||
|
setDisplayScaleFactor(VUtils::calculateScaleFactor());
|
||||||
|
|
||||||
updateFontAndPalette();
|
updateFontAndPalette();
|
||||||
|
|
||||||
updateConfig();
|
updateConfig();
|
||||||
|
@ -314,6 +314,17 @@ VDirectory *VNote::getInternalDirectory(const QString &p_path)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VNotebook *VNote::getNotebook(const QString &p_path)
|
||||||
|
{
|
||||||
|
for (auto & nb : m_notebooks) {
|
||||||
|
if (VUtils::equalPath(nb->getPath(), p_path)) {
|
||||||
|
return nb;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
void VNote::freeOrphanFiles()
|
void VNote::freeOrphanFiles()
|
||||||
{
|
{
|
||||||
for (int i = 0; i < m_externalFiles.size();) {
|
for (int i = 0; i < m_externalFiles.size();) {
|
||||||
|
@ -95,6 +95,10 @@ public:
|
|||||||
// Otherwise, returns NULL.
|
// Otherwise, returns NULL.
|
||||||
VDirectory *getInternalDirectory(const QString &p_path);
|
VDirectory *getInternalDirectory(const QString &p_path);
|
||||||
|
|
||||||
|
// Given the path of a file, try to find it in all notebooks.
|
||||||
|
// Returns a VNotebook struct if it is the root folder of a notebook.
|
||||||
|
VNotebook *getNotebook(const QString &p_path);
|
||||||
|
|
||||||
void freeOrphanFiles();
|
void freeOrphanFiles();
|
||||||
|
|
||||||
// @p_renderBg: background color, empty to not specify given color.
|
// @p_renderBg: background color, empty to not specify given color.
|
||||||
|
@ -243,5 +243,10 @@
|
|||||||
<file>resources/themes/v_moonlight/arrow_dropdown_disabled.svg</file>
|
<file>resources/themes/v_moonlight/arrow_dropdown_disabled.svg</file>
|
||||||
<file>resources/themes/v_pure/arrow_dropdown_disabled.svg</file>
|
<file>resources/themes/v_pure/arrow_dropdown_disabled.svg</file>
|
||||||
<file>resources/themes/v_white/arrow_dropdown_disabled.svg</file>
|
<file>resources/themes/v_white/arrow_dropdown_disabled.svg</file>
|
||||||
|
<file>resources/icons/clear_search.svg</file>
|
||||||
|
<file>resources/icons/search.svg</file>
|
||||||
|
<file>resources/icons/search_advanced.svg</file>
|
||||||
|
<file>resources/icons/search_console.svg</file>
|
||||||
|
<file>resources/icons/note_item.svg</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
@ -7,7 +7,6 @@
|
|||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QStyleFactory>
|
#include <QStyleFactory>
|
||||||
#include <QWidgetAction>
|
#include <QWidgetAction>
|
||||||
#include <QLabel>
|
|
||||||
|
|
||||||
#include "veditwindow.h"
|
#include "veditwindow.h"
|
||||||
#include "vnotefile.h"
|
#include "vnotefile.h"
|
||||||
|
418
src/vsearch.cpp
Normal file
418
src/vsearch.cpp
Normal file
@ -0,0 +1,418 @@
|
|||||||
|
#include "vsearch.h"
|
||||||
|
|
||||||
|
#include "utils/vutils.h"
|
||||||
|
#include "vfile.h"
|
||||||
|
#include "vdirectory.h"
|
||||||
|
#include "vnotebook.h"
|
||||||
|
#include "veditarea.h"
|
||||||
|
#include "vmainwindow.h"
|
||||||
|
#include "vtableofcontent.h"
|
||||||
|
#include "vsearchengine.h"
|
||||||
|
|
||||||
|
extern VMainWindow *g_mainWin;
|
||||||
|
|
||||||
|
VSearch::VSearch(QObject *p_parent)
|
||||||
|
: QObject(p_parent),
|
||||||
|
m_askedToStop(false),
|
||||||
|
m_engine(NULL)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QSharedPointer<VSearchResult> VSearch::search(const QVector<VFile *> &p_files)
|
||||||
|
{
|
||||||
|
Q_ASSERT(!askedToStop());
|
||||||
|
|
||||||
|
QSharedPointer<VSearchResult> result(new VSearchResult(this));
|
||||||
|
|
||||||
|
if (p_files.isEmpty()) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!testTarget(VSearchConfig::Note)) {
|
||||||
|
qDebug() << "search is not applicable for note";
|
||||||
|
result->m_state = VSearchState::Success;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
result->m_state = VSearchState::Busy;
|
||||||
|
|
||||||
|
for (auto const & it : p_files) {
|
||||||
|
if (!it) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
searchFirstPhase(it, result, true);
|
||||||
|
|
||||||
|
if (askedToStop()) {
|
||||||
|
qDebug() << "asked to cancel the search";
|
||||||
|
result->m_state = VSearchState::Cancelled;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result->m_state == VSearchState::Busy) {
|
||||||
|
result->m_state = VSearchState::Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
QSharedPointer<VSearchResult> VSearch::search(VDirectory *p_directory)
|
||||||
|
{
|
||||||
|
Q_ASSERT(!askedToStop());
|
||||||
|
|
||||||
|
QSharedPointer<VSearchResult> result(new VSearchResult(this));
|
||||||
|
|
||||||
|
if (!p_directory) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((!testTarget(VSearchConfig::Note)
|
||||||
|
&& !testTarget(VSearchConfig::Folder))
|
||||||
|
|| testObject(VSearchConfig::Outline)) {
|
||||||
|
qDebug() << "search is not applicable for folder";
|
||||||
|
result->m_state = VSearchState::Success;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
result->m_state = VSearchState::Busy;
|
||||||
|
|
||||||
|
searchFirstPhase(p_directory, result);
|
||||||
|
|
||||||
|
if (result->hasSecondPhaseItems()) {
|
||||||
|
searchSecondPhase(result);
|
||||||
|
} else if (result->m_state == VSearchState::Busy) {
|
||||||
|
result->m_state = VSearchState::Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
QSharedPointer<VSearchResult> VSearch::search(const QVector<VNotebook *> &p_notebooks)
|
||||||
|
{
|
||||||
|
Q_ASSERT(!askedToStop());
|
||||||
|
|
||||||
|
QSharedPointer<VSearchResult> result(new VSearchResult(this));
|
||||||
|
|
||||||
|
if (p_notebooks.isEmpty()) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (testObject(VSearchConfig::Outline)) {
|
||||||
|
qDebug() << "search is not applicable for notebook";
|
||||||
|
result->m_state = VSearchState::Success;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
result->m_state = VSearchState::Busy;
|
||||||
|
|
||||||
|
for (auto const & nb : p_notebooks) {
|
||||||
|
if (!nb) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
searchFirstPhase(nb, result);
|
||||||
|
|
||||||
|
if (askedToStop()) {
|
||||||
|
qDebug() << "asked to cancel the search";
|
||||||
|
result->m_state = VSearchState::Cancelled;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result->hasSecondPhaseItems()) {
|
||||||
|
searchSecondPhase(result);
|
||||||
|
} else if (result->m_state == VSearchState::Busy) {
|
||||||
|
result->m_state = VSearchState::Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VSearch::searchFirstPhase(VFile *p_file,
|
||||||
|
const QSharedPointer<VSearchResult> &p_result,
|
||||||
|
bool p_searchContent)
|
||||||
|
{
|
||||||
|
Q_ASSERT(testTarget(VSearchConfig::Note));
|
||||||
|
|
||||||
|
QString name = p_file->getName();
|
||||||
|
if (!m_patternReg.isEmpty()) {
|
||||||
|
if (!matchOneLine(name, m_patternReg)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString filePath = p_file->fetchPath();
|
||||||
|
if (testObject(VSearchConfig::Name)) {
|
||||||
|
if (matchOneLine(name, m_searchReg)) {
|
||||||
|
VSearchResultItem *item = new VSearchResultItem(VSearchResultItem::Note,
|
||||||
|
VSearchResultItem::LineNumber,
|
||||||
|
name,
|
||||||
|
filePath);
|
||||||
|
QSharedPointer<VSearchResultItem> pitem(item);
|
||||||
|
emit resultItemAdded(pitem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (testObject(VSearchConfig::Outline)) {
|
||||||
|
VSearchResultItem *item = searchForOutline(p_file);
|
||||||
|
if (item) {
|
||||||
|
QSharedPointer<VSearchResultItem> pitem(item);
|
||||||
|
emit resultItemAdded(pitem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (testObject(VSearchConfig::Content)) {
|
||||||
|
// Search content in first phase.
|
||||||
|
if (p_searchContent) {
|
||||||
|
VSearchResultItem *item = searchForContent(p_file);
|
||||||
|
if (item) {
|
||||||
|
QSharedPointer<VSearchResultItem> pitem(item);
|
||||||
|
emit resultItemAdded(pitem);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Add an item for second phase process.
|
||||||
|
p_result->addSecondPhaseItem(filePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VSearch::searchFirstPhase(VDirectory *p_directory,
|
||||||
|
const QSharedPointer<VSearchResult> &p_result)
|
||||||
|
{
|
||||||
|
if (!testTarget(VSearchConfig::Note)
|
||||||
|
&& !testTarget(VSearchConfig::Folder)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool opened = p_directory->isOpened();
|
||||||
|
if (!opened && !p_directory->open()) {
|
||||||
|
p_result->logError(QString("Fail to open folder %1.").arg(p_directory->fetchRelativePath()));
|
||||||
|
p_result->m_state = VSearchState::Fail;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (testTarget(VSearchConfig::Folder)
|
||||||
|
&& testObject(VSearchConfig::Name)) {
|
||||||
|
QString text = p_directory->getName();
|
||||||
|
if (matchOneLine(text, m_searchReg)) {
|
||||||
|
VSearchResultItem *item = new VSearchResultItem(VSearchResultItem::Folder,
|
||||||
|
VSearchResultItem::LineNumber,
|
||||||
|
text,
|
||||||
|
p_directory->fetchPath());
|
||||||
|
QSharedPointer<VSearchResultItem> pitem(item);
|
||||||
|
emit resultItemAdded(pitem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search files.
|
||||||
|
if (testTarget(VSearchConfig::Note)) {
|
||||||
|
for (auto const & file : p_directory->getFiles()) {
|
||||||
|
if (askedToStop()) {
|
||||||
|
qDebug() << "asked to cancel the search";
|
||||||
|
p_result->m_state = VSearchState::Cancelled;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
searchFirstPhase(file, p_result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search subfolders.
|
||||||
|
for (auto const & dir : p_directory->getSubDirs()) {
|
||||||
|
if (askedToStop()) {
|
||||||
|
qDebug() << "asked to cancel the search";
|
||||||
|
p_result->m_state = VSearchState::Cancelled;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
searchFirstPhase(dir, p_result);
|
||||||
|
}
|
||||||
|
|
||||||
|
exit:
|
||||||
|
if (!opened) {
|
||||||
|
p_directory->close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VSearch::searchFirstPhase(VNotebook *p_notebook,
|
||||||
|
const QSharedPointer<VSearchResult> &p_result)
|
||||||
|
{
|
||||||
|
bool opened = p_notebook->isOpened();
|
||||||
|
if (!opened && !p_notebook->open()) {
|
||||||
|
p_result->logError(QString("Fail to open notebook %1.").arg(p_notebook->getName()));
|
||||||
|
p_result->m_state = VSearchState::Fail;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (testTarget(VSearchConfig::Notebook)
|
||||||
|
&& testObject(VSearchConfig::Name)) {
|
||||||
|
QString text = p_notebook->getName();
|
||||||
|
if (matchOneLine(text, m_searchReg)) {
|
||||||
|
VSearchResultItem *item = new VSearchResultItem(VSearchResultItem::Notebook,
|
||||||
|
VSearchResultItem::LineNumber,
|
||||||
|
text,
|
||||||
|
p_notebook->getPath());
|
||||||
|
QSharedPointer<VSearchResultItem> pitem(item);
|
||||||
|
emit resultItemAdded(pitem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!testTarget(VSearchConfig::Note)
|
||||||
|
&& !testTarget(VSearchConfig::Folder)) {
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search for subfolders.
|
||||||
|
for (auto const & dir : p_notebook->getRootDir()->getSubDirs()) {
|
||||||
|
if (askedToStop()) {
|
||||||
|
qDebug() << "asked to cancel the search";
|
||||||
|
p_result->m_state = VSearchState::Cancelled;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
searchFirstPhase(dir, p_result);
|
||||||
|
}
|
||||||
|
|
||||||
|
exit:
|
||||||
|
if (!opened) {
|
||||||
|
p_notebook->close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VSearchResultItem *VSearch::searchForOutline(const VFile *p_file) const
|
||||||
|
{
|
||||||
|
VEditTab *tab = g_mainWin->getEditArea()->getTab(p_file);
|
||||||
|
if (!tab) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const VTableOfContent &toc = tab->getOutline();
|
||||||
|
const QVector<VTableOfContentItem> &table = toc.getTable();
|
||||||
|
VSearchResultItem *item = NULL;
|
||||||
|
for (auto const & it: table) {
|
||||||
|
if (it.isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!matchOneLine(it.m_name, m_searchReg)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!item) {
|
||||||
|
item = new VSearchResultItem(VSearchResultItem::Note,
|
||||||
|
VSearchResultItem::OutlineIndex,
|
||||||
|
p_file->getName(),
|
||||||
|
p_file->fetchPath());
|
||||||
|
}
|
||||||
|
|
||||||
|
VSearchResultSubItem sitem(it.m_index, it.m_name);
|
||||||
|
item->m_matches.append(sitem);
|
||||||
|
}
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
VSearchResultItem *VSearch::searchForContent(const VFile *p_file) const
|
||||||
|
{
|
||||||
|
Q_ASSERT(p_file->isOpened());
|
||||||
|
const QString &content = p_file->getContent();
|
||||||
|
if (content.isEmpty()) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
VSearchResultItem *item = NULL;
|
||||||
|
int lineNum = 1;
|
||||||
|
int pos = 0;
|
||||||
|
int size = content.size();
|
||||||
|
QRegExp newLineReg = QRegExp("\\n|\\r\\n|\\r");
|
||||||
|
Qt::CaseSensitivity cs = testOption(VSearchConfig::CaseSensitive)
|
||||||
|
? Qt::CaseSensitive : Qt::CaseInsensitive;
|
||||||
|
while (pos < size) {
|
||||||
|
int idx = content.indexOf(newLineReg, pos);
|
||||||
|
if (idx == -1) {
|
||||||
|
idx = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (idx > pos) {
|
||||||
|
QString lineText = content.mid(pos, idx - pos);
|
||||||
|
bool matched = false;
|
||||||
|
if (m_contentSearchReg.isEmpty()) {
|
||||||
|
matched = lineText.contains(m_config->m_keyword, cs);
|
||||||
|
} else {
|
||||||
|
matched = (m_contentSearchReg.indexIn(lineText) != -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (matched) {
|
||||||
|
if (!item) {
|
||||||
|
item = new VSearchResultItem(VSearchResultItem::Note,
|
||||||
|
VSearchResultItem::LineNumber,
|
||||||
|
p_file->getName(),
|
||||||
|
p_file->fetchPath());
|
||||||
|
}
|
||||||
|
|
||||||
|
VSearchResultSubItem sitem(lineNum, lineText);
|
||||||
|
item->m_matches.append(sitem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (idx == size) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
pos = idx + newLineReg.matchedLength();
|
||||||
|
++lineNum;
|
||||||
|
}
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VSearch::searchSecondPhase(const QSharedPointer<VSearchResult> &p_result)
|
||||||
|
{
|
||||||
|
delete m_engine;
|
||||||
|
m_engine = NULL;
|
||||||
|
|
||||||
|
switch (m_config->m_engine) {
|
||||||
|
case VSearchConfig::Internal:
|
||||||
|
{
|
||||||
|
m_engine = new VSearchEngine(this);
|
||||||
|
m_engine->search(m_config, p_result);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
p_result->m_state = VSearchState::Success;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_engine) {
|
||||||
|
connect(m_engine, &ISearchEngine::finished,
|
||||||
|
this, &VSearch::finished);
|
||||||
|
connect(m_engine, &ISearchEngine::resultItemAdded,
|
||||||
|
this, &VSearch::resultItemAdded);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VSearch::clear()
|
||||||
|
{
|
||||||
|
m_config.clear();
|
||||||
|
|
||||||
|
if (m_engine) {
|
||||||
|
m_engine->clear();
|
||||||
|
|
||||||
|
delete m_engine;
|
||||||
|
m_engine = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_askedToStop = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VSearch::stop()
|
||||||
|
{
|
||||||
|
qDebug() << "VSearch asked to stop";
|
||||||
|
m_askedToStop = true;
|
||||||
|
|
||||||
|
if (m_engine) {
|
||||||
|
m_engine->stop();
|
||||||
|
}
|
||||||
|
}
|
162
src/vsearch.h
Normal file
162
src/vsearch.h
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
#ifndef VSEARCH_H
|
||||||
|
#define VSEARCH_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QString>
|
||||||
|
#include <QSharedPointer>
|
||||||
|
#include <QRegExp>
|
||||||
|
#include <QCoreApplication>
|
||||||
|
|
||||||
|
#include "vsearchconfig.h"
|
||||||
|
|
||||||
|
class VFile;
|
||||||
|
class VDirectory;
|
||||||
|
class VNotebook;
|
||||||
|
class ISearchEngine;
|
||||||
|
|
||||||
|
|
||||||
|
class VSearch : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit VSearch(QObject *p_parent = nullptr);
|
||||||
|
|
||||||
|
void setConfig(QSharedPointer<VSearchConfig> p_config);
|
||||||
|
|
||||||
|
// Search list of files for CurrentNote and OpenedNotes.
|
||||||
|
QSharedPointer<VSearchResult> search(const QVector<VFile *> &p_files);
|
||||||
|
|
||||||
|
// Search folder for CurrentFolder.
|
||||||
|
QSharedPointer<VSearchResult> search(VDirectory *p_directory);
|
||||||
|
|
||||||
|
// Search folder for CurrentNotebook and AllNotebooks.
|
||||||
|
QSharedPointer<VSearchResult> search(const QVector<VNotebook *> &p_notebooks);
|
||||||
|
|
||||||
|
// Clear resources after a search completed.
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
void stop();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
// Emitted when a new item added as result.
|
||||||
|
void resultItemAdded(const QSharedPointer<VSearchResultItem> &p_item);
|
||||||
|
|
||||||
|
// Emitted when async task finished.
|
||||||
|
void finished(const QSharedPointer<VSearchResult> &p_result);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool askedToStop() const;
|
||||||
|
|
||||||
|
// @p_searchContent: whether search content in first phase.
|
||||||
|
void searchFirstPhase(VFile *p_file,
|
||||||
|
const QSharedPointer<VSearchResult> &p_result,
|
||||||
|
bool p_searchContent = false);
|
||||||
|
|
||||||
|
void searchFirstPhase(VDirectory *p_directory,
|
||||||
|
const QSharedPointer<VSearchResult> &p_result);
|
||||||
|
|
||||||
|
void searchFirstPhase(VNotebook *p_notebook,
|
||||||
|
const QSharedPointer<VSearchResult> &p_result);
|
||||||
|
|
||||||
|
bool testTarget(VSearchConfig::Target p_target) const;
|
||||||
|
|
||||||
|
bool testObject(VSearchConfig::Object p_object) const;
|
||||||
|
|
||||||
|
bool testOption(VSearchConfig::Option p_option) const;
|
||||||
|
|
||||||
|
bool matchOneLine(const QString &p_text, const QRegExp &p_reg) const;
|
||||||
|
|
||||||
|
VSearchResultItem *searchForOutline(const VFile *p_file) const;
|
||||||
|
|
||||||
|
VSearchResultItem *searchForContent(const VFile *p_file) const;
|
||||||
|
|
||||||
|
void searchSecondPhase(const QSharedPointer<VSearchResult> &p_result);
|
||||||
|
|
||||||
|
bool m_askedToStop;
|
||||||
|
|
||||||
|
QSharedPointer<VSearchConfig> m_config;
|
||||||
|
|
||||||
|
ISearchEngine *m_engine;
|
||||||
|
|
||||||
|
// Search reg used for name, outline, tag.
|
||||||
|
QRegExp m_searchReg;
|
||||||
|
|
||||||
|
// Search reg used for content.
|
||||||
|
// We use raw string to speed up if it is empty.
|
||||||
|
QRegExp m_contentSearchReg;
|
||||||
|
|
||||||
|
// Wildcard reg to for file name pattern.
|
||||||
|
QRegExp m_patternReg;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline bool VSearch::askedToStop() const
|
||||||
|
{
|
||||||
|
QCoreApplication::processEvents();
|
||||||
|
return m_askedToStop;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void VSearch::setConfig(QSharedPointer<VSearchConfig> p_config)
|
||||||
|
{
|
||||||
|
m_config = p_config;
|
||||||
|
|
||||||
|
// Compile reg.
|
||||||
|
const QString &keyword = m_config->m_keyword;
|
||||||
|
m_contentSearchReg = QRegExp();
|
||||||
|
if (keyword.isEmpty()) {
|
||||||
|
m_searchReg = QRegExp();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Qt::CaseSensitivity cs = testOption(VSearchConfig::CaseSensitive)
|
||||||
|
? Qt::CaseSensitive : Qt::CaseInsensitive;
|
||||||
|
if (testOption(VSearchConfig::RegularExpression)) {
|
||||||
|
m_searchReg = QRegExp(keyword, cs);
|
||||||
|
m_contentSearchReg = QRegExp(keyword, cs);
|
||||||
|
} else {
|
||||||
|
if (testOption(VSearchConfig::Fuzzy)) {
|
||||||
|
QString wildcardText(keyword.size() * 2 + 1, '*');
|
||||||
|
for (int i = 0, j = 1; i < keyword.size(); ++i, j += 2) {
|
||||||
|
wildcardText[j] = keyword[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
m_searchReg = QRegExp(wildcardText, cs, QRegExp::Wildcard);
|
||||||
|
} else {
|
||||||
|
QString pattern = QRegExp::escape(keyword);
|
||||||
|
if (testOption(VSearchConfig::WholeWordOnly)) {
|
||||||
|
pattern = "\\b" + pattern + "\\b";
|
||||||
|
|
||||||
|
// We only use m_contentSearchReg when WholeWordOnly is checked.
|
||||||
|
m_contentSearchReg = QRegExp(pattern, cs);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_searchReg = QRegExp(pattern, cs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_config->m_pattern.isEmpty()) {
|
||||||
|
m_patternReg = QRegExp();
|
||||||
|
} else {
|
||||||
|
m_patternReg = QRegExp(m_config->m_pattern, Qt::CaseInsensitive, QRegExp::Wildcard);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool VSearch::testTarget(VSearchConfig::Target p_target) const
|
||||||
|
{
|
||||||
|
return p_target & m_config->m_target;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool VSearch::testObject(VSearchConfig::Object p_object) const
|
||||||
|
{
|
||||||
|
return p_object & m_config->m_object;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool VSearch::testOption(VSearchConfig::Option p_option) const
|
||||||
|
{
|
||||||
|
return p_option & m_config->m_option;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool VSearch::matchOneLine(const QString &p_text, const QRegExp &p_reg) const
|
||||||
|
{
|
||||||
|
return p_reg.indexIn(p_text) != -1;
|
||||||
|
}
|
||||||
|
#endif // VSEARCH_H
|
273
src/vsearchconfig.h
Normal file
273
src/vsearchconfig.h
Normal file
@ -0,0 +1,273 @@
|
|||||||
|
#ifndef VSEARCHCONFIG_H
|
||||||
|
#define VSEARCHCONFIG_H
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
#include <QStringList>
|
||||||
|
#include <QSharedPointer>
|
||||||
|
|
||||||
|
|
||||||
|
struct VSearchConfig
|
||||||
|
{
|
||||||
|
enum Scope
|
||||||
|
{
|
||||||
|
NoneScope = 0,
|
||||||
|
CurrentNote,
|
||||||
|
OpenedNotes,
|
||||||
|
CurrentFolder,
|
||||||
|
CurrentNotebook,
|
||||||
|
AllNotebooks
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Object
|
||||||
|
{
|
||||||
|
NoneObject = 0,
|
||||||
|
Name = 0x1UL,
|
||||||
|
Content = 0x2UL,
|
||||||
|
Outline = 0x4UL,
|
||||||
|
Tag = 0x8UL
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Target
|
||||||
|
{
|
||||||
|
NoneTarget = 0,
|
||||||
|
Note = 0x1UL,
|
||||||
|
Folder = 0x2UL,
|
||||||
|
Notebook = 0x4UL
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Engine
|
||||||
|
{
|
||||||
|
Internal = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Option
|
||||||
|
{
|
||||||
|
NoneOption = 0,
|
||||||
|
CaseSensitive = 0x1UL,
|
||||||
|
WholeWordOnly = 0x2UL,
|
||||||
|
Fuzzy = 0x4UL,
|
||||||
|
RegularExpression = 0x8UL
|
||||||
|
};
|
||||||
|
|
||||||
|
VSearchConfig()
|
||||||
|
: VSearchConfig(Scope::NoneScope,
|
||||||
|
Object::NoneObject,
|
||||||
|
Target::NoneTarget,
|
||||||
|
Engine::Internal,
|
||||||
|
Option::NoneOption,
|
||||||
|
"",
|
||||||
|
"")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
VSearchConfig(int p_scope,
|
||||||
|
int p_object,
|
||||||
|
int p_target,
|
||||||
|
int p_engine,
|
||||||
|
int p_option,
|
||||||
|
const QString &p_keyword,
|
||||||
|
const QString &p_pattern)
|
||||||
|
: m_scope(p_scope),
|
||||||
|
m_object(p_object),
|
||||||
|
m_target(p_target),
|
||||||
|
m_engine(p_engine),
|
||||||
|
m_option(p_option),
|
||||||
|
m_keyword(p_keyword),
|
||||||
|
m_pattern(p_pattern)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList toConfig() const
|
||||||
|
{
|
||||||
|
QStringList str;
|
||||||
|
str << QString::number(m_scope);
|
||||||
|
str << QString::number(m_object);
|
||||||
|
str << QString::number(m_target);
|
||||||
|
str << QString::number(m_engine);
|
||||||
|
str << QString::number(m_option);
|
||||||
|
str << m_pattern;
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
static VSearchConfig fromConfig(const QStringList &p_str)
|
||||||
|
{
|
||||||
|
VSearchConfig config;
|
||||||
|
if (p_str.size() != 6) {
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
config.m_scope = p_str[0].toInt();
|
||||||
|
config.m_object = p_str[1].toInt();
|
||||||
|
config.m_target = p_str[2].toInt();
|
||||||
|
config.m_engine = p_str[3].toInt();
|
||||||
|
config.m_option = p_str[4].toInt();
|
||||||
|
config.m_pattern = p_str[5];
|
||||||
|
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
int m_scope;
|
||||||
|
int m_object;
|
||||||
|
int m_target;
|
||||||
|
int m_engine;
|
||||||
|
int m_option;
|
||||||
|
|
||||||
|
QString m_keyword;
|
||||||
|
|
||||||
|
// Wildcard pattern to filter file.
|
||||||
|
QString m_pattern;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct VSearchResultSubItem
|
||||||
|
{
|
||||||
|
VSearchResultSubItem()
|
||||||
|
: m_lineNumber(-1)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
VSearchResultSubItem(int p_lineNumber,
|
||||||
|
const QString &p_text)
|
||||||
|
: m_lineNumber(p_lineNumber),
|
||||||
|
m_text(p_text)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int m_lineNumber;
|
||||||
|
|
||||||
|
QString m_text;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct VSearchResultItem
|
||||||
|
{
|
||||||
|
enum ItemType
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
Note,
|
||||||
|
Folder,
|
||||||
|
Notebook
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
enum MatchType
|
||||||
|
{
|
||||||
|
LineNumber = 0,
|
||||||
|
OutlineIndex
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
VSearchResultItem()
|
||||||
|
: m_type(ItemType::None),
|
||||||
|
m_matchType(MatchType::LineNumber)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
VSearchResultItem(VSearchResultItem::ItemType p_type,
|
||||||
|
VSearchResultItem::MatchType p_matchType,
|
||||||
|
const QString &p_text,
|
||||||
|
const QString &p_path)
|
||||||
|
: m_type(p_type),
|
||||||
|
m_matchType(p_matchType),
|
||||||
|
m_text(p_text),
|
||||||
|
m_path(p_path)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isEmpty() const
|
||||||
|
{
|
||||||
|
return m_type == ItemType::None;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString toString() const
|
||||||
|
{
|
||||||
|
return QString("item text: [%1] path: [%2] subitems: %3")
|
||||||
|
.arg(m_text)
|
||||||
|
.arg(m_path)
|
||||||
|
.arg(m_matches.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ItemType m_type;
|
||||||
|
|
||||||
|
MatchType m_matchType;
|
||||||
|
|
||||||
|
// Text to displayed. If empty, use @m_path instead.
|
||||||
|
QString m_text;
|
||||||
|
|
||||||
|
// Path of the target.
|
||||||
|
QString m_path;
|
||||||
|
|
||||||
|
// Matched places within this item.
|
||||||
|
QList<VSearchResultSubItem> m_matches;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class VSearch;
|
||||||
|
|
||||||
|
|
||||||
|
enum class VSearchState
|
||||||
|
{
|
||||||
|
Idle = 0,
|
||||||
|
Busy,
|
||||||
|
Success,
|
||||||
|
Fail,
|
||||||
|
Cancelled
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct VSearchResult
|
||||||
|
{
|
||||||
|
friend class VSearch;
|
||||||
|
|
||||||
|
VSearchResult(VSearch *p_search)
|
||||||
|
: m_state(VSearchState::Idle),
|
||||||
|
m_search(p_search)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasError() const
|
||||||
|
{
|
||||||
|
return !m_errMsg.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
void logError(const QString &p_err)
|
||||||
|
{
|
||||||
|
if (m_errMsg.isEmpty()) {
|
||||||
|
m_errMsg = p_err;
|
||||||
|
} else {
|
||||||
|
m_errMsg = "\n" + p_err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void addSecondPhaseItem(const QString &p_item)
|
||||||
|
{
|
||||||
|
m_secondPhaseItems.append(p_item);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString toString() const
|
||||||
|
{
|
||||||
|
QString str = QString("search result: state %1 err %2")
|
||||||
|
.arg((int)m_state)
|
||||||
|
.arg(!m_errMsg.isEmpty());
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasSecondPhaseItems() const
|
||||||
|
{
|
||||||
|
return !m_secondPhaseItems.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
VSearchState m_state;
|
||||||
|
|
||||||
|
QString m_errMsg;
|
||||||
|
|
||||||
|
QStringList m_secondPhaseItems;
|
||||||
|
|
||||||
|
private:
|
||||||
|
VSearch *m_search;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // VSEARCHCONFIG_H
|
255
src/vsearchengine.cpp
Normal file
255
src/vsearchengine.cpp
Normal file
@ -0,0 +1,255 @@
|
|||||||
|
#include "vsearchengine.h"
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QMimeDatabase>
|
||||||
|
|
||||||
|
#include "utils/vutils.h"
|
||||||
|
|
||||||
|
VSearchEngineWorker::VSearchEngineWorker(QObject *p_parent)
|
||||||
|
: QThread(p_parent),
|
||||||
|
m_stop(0),
|
||||||
|
m_state(VSearchState::Idle)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void VSearchEngineWorker::setData(const QStringList &p_files,
|
||||||
|
const QRegExp &p_reg,
|
||||||
|
const QString &p_keyword,
|
||||||
|
Qt::CaseSensitivity p_cs)
|
||||||
|
{
|
||||||
|
m_files = p_files;
|
||||||
|
m_reg = p_reg;
|
||||||
|
m_keyword = p_keyword;
|
||||||
|
m_caseSensitivity = p_cs;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VSearchEngineWorker::stop()
|
||||||
|
{
|
||||||
|
m_stop.store(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VSearchEngineWorker::run()
|
||||||
|
{
|
||||||
|
qDebug() << "worker" << QThread::currentThreadId() << m_files.size();
|
||||||
|
|
||||||
|
QMimeDatabase mimeDatabase;
|
||||||
|
m_state = VSearchState::Busy;
|
||||||
|
|
||||||
|
for (auto const & fileName : m_files) {
|
||||||
|
if (m_stop.load() == 1) {
|
||||||
|
m_state = VSearchState::Cancelled;
|
||||||
|
qDebug() << "worker" << QThread::currentThreadId() << "is asked to stop";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QMimeType mimeType = mimeDatabase.mimeTypeForFile(fileName);
|
||||||
|
if (mimeType.isValid() && !mimeType.inherits(QStringLiteral("text/plain"))) {
|
||||||
|
appendError(tr("Skip binary file %1.").arg(fileName));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
VSearchResultItem *item = searchFile(fileName);
|
||||||
|
if (item) {
|
||||||
|
emit resultItemReady(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_state == VSearchState::Busy) {
|
||||||
|
m_state = VSearchState::Success;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VSearchResultItem *VSearchEngineWorker::searchFile(const QString &p_fileName)
|
||||||
|
{
|
||||||
|
QFile file(p_fileName);
|
||||||
|
if (!file.open(QIODevice::ReadOnly)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lineNum = 1;
|
||||||
|
VSearchResultItem *item = NULL;
|
||||||
|
QString line;
|
||||||
|
QTextStream in(&file);
|
||||||
|
while (!in.atEnd()) {
|
||||||
|
if (m_stop.load() == 1) {
|
||||||
|
m_state = VSearchState::Cancelled;
|
||||||
|
qDebug() << "worker" << QThread::currentThreadId() << "is asked to stop";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool matched = false;
|
||||||
|
line = in.readLine();
|
||||||
|
if (m_reg.isEmpty()) {
|
||||||
|
if (line.contains(m_keyword, m_caseSensitivity)) {
|
||||||
|
matched = true;
|
||||||
|
}
|
||||||
|
} else if (m_reg.indexIn(line) != -1) {
|
||||||
|
matched = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (matched) {
|
||||||
|
if (!item) {
|
||||||
|
item = new VSearchResultItem(VSearchResultItem::Note,
|
||||||
|
VSearchResultItem::LineNumber,
|
||||||
|
VUtils::fileNameFromPath(p_fileName),
|
||||||
|
p_fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
VSearchResultSubItem sitem(lineNum, line);
|
||||||
|
item->m_matches.append(sitem);
|
||||||
|
}
|
||||||
|
|
||||||
|
++lineNum;
|
||||||
|
}
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
VSearchEngine::VSearchEngine(QObject *p_parent)
|
||||||
|
: ISearchEngine(p_parent),
|
||||||
|
m_finishedWorkers(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void VSearchEngine::search(const QSharedPointer<VSearchConfig> &p_config,
|
||||||
|
const QSharedPointer<VSearchResult> &p_result)
|
||||||
|
{
|
||||||
|
int numThread = QThread::idealThreadCount();
|
||||||
|
if (numThread < 1) {
|
||||||
|
numThread = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QStringList items = p_result->m_secondPhaseItems;
|
||||||
|
Q_ASSERT(!items.isEmpty());
|
||||||
|
if (items.size() < numThread) {
|
||||||
|
numThread = items.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_result = p_result;
|
||||||
|
|
||||||
|
QRegExp reg = compileRegExpFromConfig(p_config);
|
||||||
|
Qt::CaseSensitivity cs = (p_config->m_option & VSearchConfig::CaseSensitive)
|
||||||
|
? Qt::CaseSensitive : Qt::CaseInsensitive;
|
||||||
|
|
||||||
|
clearAllWorkers();
|
||||||
|
m_workers.reserve(numThread);
|
||||||
|
m_finishedWorkers = 0;
|
||||||
|
int totalSize = m_result->m_secondPhaseItems.size();
|
||||||
|
int step = totalSize / numThread;
|
||||||
|
int remain = totalSize % numThread;
|
||||||
|
|
||||||
|
for (int i = 0; i < numThread; ++i) {
|
||||||
|
int start = i * step;
|
||||||
|
if (start >= totalSize) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
int len = step;
|
||||||
|
if (remain) {
|
||||||
|
++len;
|
||||||
|
--remain;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (start + len > totalSize) {
|
||||||
|
len = totalSize - start;
|
||||||
|
}
|
||||||
|
|
||||||
|
VSearchEngineWorker *th = new VSearchEngineWorker(this);
|
||||||
|
th->setData(m_result->m_secondPhaseItems.mid(start, len),
|
||||||
|
reg,
|
||||||
|
p_config->m_keyword,
|
||||||
|
cs);
|
||||||
|
connect(th, &VSearchEngineWorker::finished,
|
||||||
|
this, &VSearchEngine::handleWorkerFinished);
|
||||||
|
connect(th, &VSearchEngineWorker::resultItemReady,
|
||||||
|
this, [this](VSearchResultItem *p_item) {
|
||||||
|
emit resultItemAdded(QSharedPointer<VSearchResultItem>(p_item));
|
||||||
|
});
|
||||||
|
|
||||||
|
m_workers.append(th);
|
||||||
|
th->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
qDebug() << "schedule tasks to threads" << m_workers.size() << totalSize << step;
|
||||||
|
}
|
||||||
|
|
||||||
|
QRegExp VSearchEngine::compileRegExpFromConfig(const QSharedPointer<VSearchConfig> &p_config) const
|
||||||
|
{
|
||||||
|
const QString &keyword = p_config->m_keyword;
|
||||||
|
Qt::CaseSensitivity cs = (p_config->m_option & VSearchConfig::CaseSensitive)
|
||||||
|
? Qt::CaseSensitive : Qt::CaseInsensitive;
|
||||||
|
if (p_config->m_option & VSearchConfig::RegularExpression) {
|
||||||
|
return QRegExp(keyword, cs);
|
||||||
|
} else if (p_config->m_option & VSearchConfig::WholeWordOnly) {
|
||||||
|
QString pattern = QRegExp::escape(keyword);
|
||||||
|
pattern = "\\b" + pattern + "\\b";
|
||||||
|
return QRegExp(pattern, cs);
|
||||||
|
} else {
|
||||||
|
return QRegExp();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VSearchEngine::stop()
|
||||||
|
{
|
||||||
|
qDebug() << "VSearchEngine asked to stop";
|
||||||
|
for (auto const & th : m_workers) {
|
||||||
|
th->stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VSearchEngine::handleWorkerFinished()
|
||||||
|
{
|
||||||
|
++m_finishedWorkers;
|
||||||
|
|
||||||
|
qDebug() << m_finishedWorkers << "workers finished";
|
||||||
|
if (m_finishedWorkers == m_workers.size()) {
|
||||||
|
VSearchState state = VSearchState::Success;
|
||||||
|
|
||||||
|
for (auto const & th : m_workers) {
|
||||||
|
if (th->m_state == VSearchState::Fail) {
|
||||||
|
if (state != VSearchState::Cancelled) {
|
||||||
|
state = VSearchState::Fail;
|
||||||
|
}
|
||||||
|
} else if (th->m_state == VSearchState::Cancelled) {
|
||||||
|
state = VSearchState::Cancelled;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!th->m_error.isEmpty()) {
|
||||||
|
m_result->logError(th->m_error);
|
||||||
|
}
|
||||||
|
|
||||||
|
Q_ASSERT(th->isFinished());
|
||||||
|
th->deleteLater();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_workers.clear();
|
||||||
|
m_finishedWorkers = 0;
|
||||||
|
|
||||||
|
m_result->m_state = state;
|
||||||
|
qDebug() << "SearchEngine finished" << (int)state;
|
||||||
|
emit finished(m_result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VSearchEngine::clear()
|
||||||
|
{
|
||||||
|
clearAllWorkers();
|
||||||
|
|
||||||
|
m_finishedWorkers = 0;
|
||||||
|
|
||||||
|
m_result.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VSearchEngine::clearAllWorkers()
|
||||||
|
{
|
||||||
|
for (auto const & th : m_workers) {
|
||||||
|
th->quit();
|
||||||
|
th->wait();
|
||||||
|
|
||||||
|
delete th;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_workers.clear();
|
||||||
|
}
|
89
src/vsearchengine.h
Normal file
89
src/vsearchengine.h
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
#ifndef VSEARCHENGINE_H
|
||||||
|
#define VSEARCHENGINE_H
|
||||||
|
|
||||||
|
#include <QThread>
|
||||||
|
#include <QRegExp>
|
||||||
|
#include <QAtomicInt>
|
||||||
|
#include "isearchengine.h"
|
||||||
|
|
||||||
|
class VSearchEngineWorker : public QThread
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
friend class VSearchEngine;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit VSearchEngineWorker(QObject *p_parent = nullptr);
|
||||||
|
|
||||||
|
void setData(const QStringList &p_files,
|
||||||
|
const QRegExp &p_reg,
|
||||||
|
const QString &p_keyword,
|
||||||
|
Qt::CaseSensitivity p_cs);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void stop();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void resultItemReady(VSearchResultItem *p_item);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void run() Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void appendError(const QString &p_err);
|
||||||
|
|
||||||
|
VSearchResultItem *searchFile(const QString &p_fileName);
|
||||||
|
|
||||||
|
QAtomicInt m_stop;
|
||||||
|
|
||||||
|
QStringList m_files;
|
||||||
|
|
||||||
|
QRegExp m_reg;
|
||||||
|
|
||||||
|
QString m_keyword;
|
||||||
|
|
||||||
|
Qt::CaseSensitivity m_caseSensitivity;
|
||||||
|
|
||||||
|
VSearchState m_state;
|
||||||
|
|
||||||
|
QString m_error;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline void VSearchEngineWorker::appendError(const QString &p_err)
|
||||||
|
{
|
||||||
|
if (m_error.isEmpty()) {
|
||||||
|
m_error = p_err;
|
||||||
|
} else {
|
||||||
|
m_error = "\n" + p_err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class VSearchEngine : public ISearchEngine
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit VSearchEngine(QObject *p_parent = nullptr);
|
||||||
|
|
||||||
|
void search(const QSharedPointer<VSearchConfig> &p_config,
|
||||||
|
const QSharedPointer<VSearchResult> &p_result) Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
|
void stop() Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
|
void clear() Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void handleWorkerFinished();
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Returns an empty object if raw string is preferred.
|
||||||
|
QRegExp compileRegExpFromConfig(const QSharedPointer<VSearchConfig> &p_config) const;
|
||||||
|
|
||||||
|
void clearAllWorkers();
|
||||||
|
|
||||||
|
int m_finishedWorkers;
|
||||||
|
|
||||||
|
QVector<VSearchEngineWorker *> m_workers;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // VSEARCHENGINE_H
|
548
src/vsearcher.cpp
Normal file
548
src/vsearcher.cpp
Normal file
@ -0,0 +1,548 @@
|
|||||||
|
#include "vsearcher.h"
|
||||||
|
|
||||||
|
#include <QtWidgets>
|
||||||
|
#include <QCoreApplication>
|
||||||
|
|
||||||
|
#include "vlineedit.h"
|
||||||
|
#include "utils/vutils.h"
|
||||||
|
#include "utils/viconutils.h"
|
||||||
|
#include "vsearch.h"
|
||||||
|
#include "vsearchresulttree.h"
|
||||||
|
#include "vmainwindow.h"
|
||||||
|
#include "veditarea.h"
|
||||||
|
#include "vdirectorytree.h"
|
||||||
|
#include "vdirectory.h"
|
||||||
|
#include "vnotebookselector.h"
|
||||||
|
#include "vnotebook.h"
|
||||||
|
#include "vnote.h"
|
||||||
|
#include "vconfigmanager.h"
|
||||||
|
|
||||||
|
extern VMainWindow *g_mainWin;
|
||||||
|
|
||||||
|
extern VNote *g_vnote;
|
||||||
|
|
||||||
|
extern VConfigManager *g_config;
|
||||||
|
|
||||||
|
VSearcher::VSearcher(QWidget *p_parent)
|
||||||
|
: QWidget(p_parent),
|
||||||
|
m_inSearch(false),
|
||||||
|
m_askedToStop(false),
|
||||||
|
m_search(this)
|
||||||
|
{
|
||||||
|
setupUI();
|
||||||
|
|
||||||
|
initUIFields();
|
||||||
|
|
||||||
|
handleInputChanged();
|
||||||
|
|
||||||
|
connect(&m_search, &VSearch::resultItemAdded,
|
||||||
|
m_results, &VSearchResultTree::addResultItem);
|
||||||
|
connect(&m_search, &VSearch::finished,
|
||||||
|
this, &VSearcher::handleSearchFinished);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VSearcher::setupUI()
|
||||||
|
{
|
||||||
|
// Search button.
|
||||||
|
m_searchBtn = new QPushButton(VIconUtils::buttonIcon(":/resources/icons/search.svg"), "", this);
|
||||||
|
m_searchBtn->setToolTip(tr("Search"));
|
||||||
|
m_searchBtn->setProperty("FlatBtn", true);
|
||||||
|
connect(m_searchBtn, &QPushButton::clicked,
|
||||||
|
this, &VSearcher::startSearch);
|
||||||
|
|
||||||
|
// Clear button.
|
||||||
|
m_clearBtn = new QPushButton(VIconUtils::buttonDangerIcon(":/resources/icons/clear_search.svg"), "", this);
|
||||||
|
m_clearBtn->setToolTip(tr("Clear Results"));
|
||||||
|
m_clearBtn->setProperty("FlatBtn", true);
|
||||||
|
connect(m_clearBtn, &QPushButton::clicked,
|
||||||
|
this, [this]() {
|
||||||
|
m_results->clearResults();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Advanced button.
|
||||||
|
m_advBtn = new QPushButton(VIconUtils::buttonIcon(":/resources/icons/search_advanced.svg"),
|
||||||
|
"",
|
||||||
|
this);
|
||||||
|
m_advBtn->setToolTip(tr("Advanced Settings"));
|
||||||
|
m_advBtn->setProperty("FlatBtn", true);
|
||||||
|
m_advBtn->setCheckable(true);
|
||||||
|
connect(m_advBtn, &QPushButton::toggled,
|
||||||
|
this, [this](bool p_checked) {
|
||||||
|
m_advWidget->setVisible(p_checked);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Console button.
|
||||||
|
m_consoleBtn = new QPushButton(VIconUtils::buttonIcon(":/resources/icons/search_console.svg"),
|
||||||
|
"",
|
||||||
|
this);
|
||||||
|
m_consoleBtn->setToolTip(tr("Console"));
|
||||||
|
m_consoleBtn->setProperty("FlatBtn", true);
|
||||||
|
m_consoleBtn->setCheckable(true);
|
||||||
|
connect(m_consoleBtn, &QPushButton::toggled,
|
||||||
|
this, [this](bool p_checked) {
|
||||||
|
m_consoleEdit->setVisible(p_checked);
|
||||||
|
});
|
||||||
|
|
||||||
|
m_numLabel = new QLabel(this);
|
||||||
|
|
||||||
|
QHBoxLayout *btnLayout = new QHBoxLayout();
|
||||||
|
btnLayout->addWidget(m_searchBtn);
|
||||||
|
btnLayout->addWidget(m_clearBtn);
|
||||||
|
btnLayout->addWidget(m_advBtn);
|
||||||
|
btnLayout->addWidget(m_consoleBtn);
|
||||||
|
btnLayout->addStretch();
|
||||||
|
btnLayout->addWidget(m_numLabel);
|
||||||
|
btnLayout->setContentsMargins(0, 0, 3, 0);
|
||||||
|
|
||||||
|
// Keyword.
|
||||||
|
m_keywordCB = VUtils::getComboBox(this);
|
||||||
|
m_keywordCB->setEditable(true);
|
||||||
|
m_keywordCB->setLineEdit(new VLineEdit(this));
|
||||||
|
m_keywordCB->setToolTip(tr("Keywords to search for"));
|
||||||
|
connect(m_keywordCB, &QComboBox::currentTextChanged,
|
||||||
|
this, &VSearcher::handleInputChanged);
|
||||||
|
connect(m_keywordCB->lineEdit(), &QLineEdit::returnPressed,
|
||||||
|
this, &VSearcher::animateSearchClick);
|
||||||
|
m_keywordCB->completer()->setCaseSensitivity(Qt::CaseSensitive);
|
||||||
|
|
||||||
|
// Scope.
|
||||||
|
m_searchScopeCB = VUtils::getComboBox(this);
|
||||||
|
m_searchScopeCB->setToolTip(tr("Scope to search"));
|
||||||
|
connect(m_searchScopeCB, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
|
||||||
|
this, &VSearcher::handleInputChanged);
|
||||||
|
|
||||||
|
// Object.
|
||||||
|
m_searchObjectCB = VUtils::getComboBox(this);
|
||||||
|
m_searchObjectCB->setToolTip(tr("Object to search"));
|
||||||
|
connect(m_searchObjectCB, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
|
||||||
|
this, &VSearcher::handleInputChanged);
|
||||||
|
|
||||||
|
// Target.
|
||||||
|
m_searchTargetCB = VUtils::getComboBox(this);
|
||||||
|
m_searchTargetCB->setToolTip(tr("Target to search"));
|
||||||
|
connect(m_searchTargetCB, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
|
||||||
|
this, &VSearcher::handleInputChanged);
|
||||||
|
|
||||||
|
// Pattern.
|
||||||
|
m_filePatternCB = VUtils::getComboBox(this);
|
||||||
|
m_filePatternCB->setEditable(true);
|
||||||
|
m_filePatternCB->setLineEdit(new VLineEdit(this));
|
||||||
|
m_filePatternCB->setToolTip(tr("Wildcard pattern to filter the files to be searched"));
|
||||||
|
m_filePatternCB->completer()->setCaseSensitivity(Qt::CaseSensitive);
|
||||||
|
|
||||||
|
// Engine.
|
||||||
|
m_searchEngineCB = VUtils::getComboBox(this);
|
||||||
|
m_searchEngineCB->setToolTip(tr("Engine to execute the search"));
|
||||||
|
|
||||||
|
// Case sensitive.
|
||||||
|
m_caseSensitiveCB = new QCheckBox(tr("&Case sensitive"), this);
|
||||||
|
|
||||||
|
// Whole word only.
|
||||||
|
m_wholeWordOnlyCB = new QCheckBox(tr("&Whole word only"), this);
|
||||||
|
|
||||||
|
// Fuzzy search.
|
||||||
|
m_fuzzyCB = new QCheckBox(tr("&Fuzzy search"), this);
|
||||||
|
m_fuzzyCB->setToolTip(tr("Not available for content search"));
|
||||||
|
connect(m_fuzzyCB, &QCheckBox::stateChanged,
|
||||||
|
this, [this](int p_state) {
|
||||||
|
bool checked = p_state == Qt::Checked;
|
||||||
|
m_wholeWordOnlyCB->setEnabled(!checked);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Regular expression.
|
||||||
|
m_regularExpressionCB = new QCheckBox(tr("Re&gular expression"), this);
|
||||||
|
connect(m_regularExpressionCB, &QCheckBox::stateChanged,
|
||||||
|
this, [this](int p_state) {
|
||||||
|
bool checked = p_state == Qt::Checked;
|
||||||
|
m_wholeWordOnlyCB->setEnabled(!checked);
|
||||||
|
m_fuzzyCB->setEnabled(!checked);
|
||||||
|
});
|
||||||
|
|
||||||
|
QFormLayout *advLayout = new QFormLayout();
|
||||||
|
advLayout->addRow(tr("File pattern:"), m_filePatternCB);
|
||||||
|
advLayout->addRow(tr("Engine:"), m_searchEngineCB);
|
||||||
|
advLayout->addRow(m_caseSensitiveCB);
|
||||||
|
advLayout->addRow(m_wholeWordOnlyCB);
|
||||||
|
advLayout->addRow(m_fuzzyCB);
|
||||||
|
advLayout->addRow(m_regularExpressionCB);
|
||||||
|
advLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
|
||||||
|
m_advWidget = new QWidget(this);
|
||||||
|
m_advWidget->setLayout(advLayout);
|
||||||
|
m_advWidget->hide();
|
||||||
|
|
||||||
|
// Progress bar.
|
||||||
|
m_proBar = new QProgressBar(this);
|
||||||
|
m_proBar->setRange(0, 0);
|
||||||
|
|
||||||
|
// Cancel button.
|
||||||
|
m_cancelBtn = new QPushButton(VIconUtils::buttonIcon(":/resources/icons/close.svg"),
|
||||||
|
"",
|
||||||
|
this);
|
||||||
|
m_cancelBtn->setToolTip(tr("Cancel"));
|
||||||
|
m_cancelBtn->setProperty("FlatBtn", true);
|
||||||
|
connect(m_cancelBtn, &QPushButton::clicked,
|
||||||
|
this, [this]() {
|
||||||
|
if (m_inSearch) {
|
||||||
|
appendLogLine(tr("Cancelling the export..."));
|
||||||
|
m_askedToStop = true;
|
||||||
|
m_search.stop();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
QHBoxLayout *proLayout = new QHBoxLayout();
|
||||||
|
proLayout->addWidget(m_proBar);
|
||||||
|
proLayout->addWidget(m_cancelBtn);
|
||||||
|
proLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
|
||||||
|
// Console.
|
||||||
|
m_consoleEdit = new QPlainTextEdit(this);
|
||||||
|
m_consoleEdit->setReadOnly(true);
|
||||||
|
m_consoleEdit->setLineWrapMode(QPlainTextEdit::WidgetWidth);
|
||||||
|
m_consoleEdit->setProperty("LineEdit", true);
|
||||||
|
m_consoleEdit->setPlaceholderText(tr("Output logs will be shown here"));
|
||||||
|
m_consoleEdit->setMaximumHeight(m_searchScopeCB->height() * 2);
|
||||||
|
m_consoleEdit->hide();
|
||||||
|
|
||||||
|
// List.
|
||||||
|
m_results = new VSearchResultTree(this);
|
||||||
|
m_results->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
|
||||||
|
connect(m_results, &VSearchResultTree::countChanged,
|
||||||
|
this, [this](int p_count) {
|
||||||
|
m_clearBtn->setEnabled(p_count > 0);
|
||||||
|
updateNumLabel(p_count);
|
||||||
|
});
|
||||||
|
|
||||||
|
QFormLayout *formLayout = new QFormLayout();
|
||||||
|
formLayout->addRow(tr("Keywords:"), m_keywordCB);
|
||||||
|
formLayout->addRow(tr("Scope:"), m_searchScopeCB);
|
||||||
|
formLayout->addRow(tr("Object:"), m_searchObjectCB);
|
||||||
|
formLayout->addRow(tr("Target:"), m_searchTargetCB);
|
||||||
|
formLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
|
||||||
|
QVBoxLayout *mainLayout = new QVBoxLayout();
|
||||||
|
mainLayout->addLayout(btnLayout);
|
||||||
|
mainLayout->addLayout(formLayout);
|
||||||
|
mainLayout->addWidget(m_advWidget);
|
||||||
|
mainLayout->addLayout(proLayout);
|
||||||
|
mainLayout->addWidget(m_consoleEdit);
|
||||||
|
mainLayout->addWidget(m_results);
|
||||||
|
|
||||||
|
setLayout(mainLayout);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VSearcher::initUIFields()
|
||||||
|
{
|
||||||
|
VSearchConfig config = VSearchConfig::fromConfig(g_config->getSearchOptions());
|
||||||
|
|
||||||
|
// Scope.
|
||||||
|
m_searchScopeCB->addItem(tr("Current Note"), VSearchConfig::CurrentNote);
|
||||||
|
m_searchScopeCB->addItem(tr("Opened Notes"), VSearchConfig::OpenedNotes);
|
||||||
|
m_searchScopeCB->addItem(tr("Current Folder"), VSearchConfig::CurrentFolder);
|
||||||
|
m_searchScopeCB->addItem(tr("Current Notebook"), VSearchConfig::CurrentNotebook);
|
||||||
|
m_searchScopeCB->addItem(tr("All Notebooks"), VSearchConfig::AllNotebooks);
|
||||||
|
m_searchScopeCB->setCurrentIndex(m_searchScopeCB->findData(config.m_scope));
|
||||||
|
|
||||||
|
// Object.
|
||||||
|
m_searchObjectCB->addItem(tr("Name"), VSearchConfig::Name);
|
||||||
|
m_searchObjectCB->addItem(tr("Content"), VSearchConfig::Content);
|
||||||
|
m_searchObjectCB->addItem(tr("Outline"), VSearchConfig::Outline);
|
||||||
|
m_searchObjectCB->setCurrentIndex(m_searchObjectCB->findData(config.m_object));
|
||||||
|
|
||||||
|
// Target.
|
||||||
|
m_searchTargetCB->addItem(tr("Note"), VSearchConfig::Note);
|
||||||
|
m_searchTargetCB->addItem(tr("Folder"), VSearchConfig::Folder);
|
||||||
|
m_searchTargetCB->addItem(tr("Notebook"), VSearchConfig::Notebook);
|
||||||
|
m_searchTargetCB->addItem(tr("All"),
|
||||||
|
VSearchConfig::Note
|
||||||
|
| VSearchConfig:: Folder
|
||||||
|
| VSearchConfig::Notebook);
|
||||||
|
m_searchTargetCB->setCurrentIndex(m_searchTargetCB->findData(config.m_target));
|
||||||
|
|
||||||
|
// Engine.
|
||||||
|
m_searchEngineCB->addItem(tr("Internal"), VSearchConfig::Internal);
|
||||||
|
m_searchEngineCB->setCurrentIndex(m_searchEngineCB->findData(config.m_engine));
|
||||||
|
|
||||||
|
// Pattern.
|
||||||
|
m_filePatternCB->setCurrentText(config.m_pattern);
|
||||||
|
|
||||||
|
m_caseSensitiveCB->setChecked(config.m_option & VSearchConfig::CaseSensitive);
|
||||||
|
m_wholeWordOnlyCB->setChecked(config.m_option & VSearchConfig::WholeWordOnly);
|
||||||
|
m_fuzzyCB->setChecked(config.m_option & VSearchConfig::Fuzzy);
|
||||||
|
m_regularExpressionCB->setChecked(config.m_option & VSearchConfig::RegularExpression);
|
||||||
|
|
||||||
|
setProgressVisible(false);
|
||||||
|
|
||||||
|
m_clearBtn->setEnabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VSearcher::updateItemToComboBox(QComboBox *p_comboBox)
|
||||||
|
{
|
||||||
|
QString text = p_comboBox->currentText();
|
||||||
|
if (!text.isEmpty() && p_comboBox->findText(text) == -1) {
|
||||||
|
p_comboBox->addItem(text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VSearcher::setProgressVisible(bool p_visible)
|
||||||
|
{
|
||||||
|
m_proBar->setVisible(p_visible);
|
||||||
|
m_cancelBtn->setVisible(p_visible);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VSearcher::appendLogLine(const QString &p_text)
|
||||||
|
{
|
||||||
|
m_consoleEdit->appendPlainText(">>> " + p_text);
|
||||||
|
m_consoleEdit->ensureCursorVisible();
|
||||||
|
QCoreApplication::sendPostedEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VSearcher::showMessage(const QString &p_text) const
|
||||||
|
{
|
||||||
|
g_mainWin->showStatusMessage(p_text);
|
||||||
|
QCoreApplication::sendPostedEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VSearcher::handleInputChanged()
|
||||||
|
{
|
||||||
|
bool readyToSearch = true;
|
||||||
|
|
||||||
|
// Keyword.
|
||||||
|
QString keyword = m_keywordCB->currentText();
|
||||||
|
readyToSearch = !keyword.isEmpty();
|
||||||
|
|
||||||
|
if (readyToSearch) {
|
||||||
|
// Other targets are only available for Name.
|
||||||
|
int obj = m_searchObjectCB->currentData().toInt();
|
||||||
|
if (obj != VSearchConfig::Name) {
|
||||||
|
int target = m_searchTargetCB->currentData().toInt();
|
||||||
|
if (!(target & VSearchConfig::Note)) {
|
||||||
|
readyToSearch = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (readyToSearch && obj == VSearchConfig::Outline) {
|
||||||
|
// Outline is available only for CurrentNote and OpenedNotes.
|
||||||
|
int scope = m_searchScopeCB->currentData().toInt();
|
||||||
|
if (scope != VSearchConfig::CurrentNote
|
||||||
|
&& scope != VSearchConfig::OpenedNotes) {
|
||||||
|
readyToSearch = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_searchBtn->setEnabled(readyToSearch);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VSearcher::startSearch()
|
||||||
|
{
|
||||||
|
if (m_inSearch) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_searchBtn->setEnabled(false);
|
||||||
|
setProgressVisible(true);
|
||||||
|
m_results->clearResults();
|
||||||
|
m_askedToStop = false;
|
||||||
|
m_inSearch = true;
|
||||||
|
m_consoleEdit->clear();
|
||||||
|
appendLogLine(tr("Search started."));
|
||||||
|
|
||||||
|
updateItemToComboBox(m_keywordCB);
|
||||||
|
updateItemToComboBox(m_filePatternCB);
|
||||||
|
|
||||||
|
QSharedPointer<VSearchConfig> config(new VSearchConfig(m_searchScopeCB->currentData().toInt(),
|
||||||
|
m_searchObjectCB->currentData().toInt(),
|
||||||
|
m_searchTargetCB->currentData().toInt(),
|
||||||
|
m_searchEngineCB->currentData().toInt(),
|
||||||
|
getSearchOption(),
|
||||||
|
m_keywordCB->currentText(),
|
||||||
|
m_filePatternCB->currentText()));
|
||||||
|
m_search.setConfig(config);
|
||||||
|
|
||||||
|
g_config->setSearchOptions(config->toConfig());
|
||||||
|
|
||||||
|
QSharedPointer<VSearchResult> result;
|
||||||
|
switch (config->m_scope) {
|
||||||
|
case VSearchConfig::CurrentNote:
|
||||||
|
{
|
||||||
|
QVector<VFile *> files;
|
||||||
|
files.append(g_mainWin->getCurrentFile());
|
||||||
|
if (files[0]) {
|
||||||
|
QString msg(tr("Search current note %1.").arg(files[0]->getName()));
|
||||||
|
appendLogLine(msg);
|
||||||
|
showMessage(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
result = m_search.search(files);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case VSearchConfig::OpenedNotes:
|
||||||
|
{
|
||||||
|
QVector<VEditTabInfo> tabs = g_mainWin->getEditArea()->getAllTabsInfo();
|
||||||
|
QVector<VFile *> files;
|
||||||
|
files.reserve(tabs.size());
|
||||||
|
for (auto const & ta : tabs) {
|
||||||
|
files.append(ta.m_editTab->getFile());
|
||||||
|
}
|
||||||
|
|
||||||
|
result = m_search.search(files);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case VSearchConfig::CurrentFolder:
|
||||||
|
{
|
||||||
|
VDirectory *dir = g_mainWin->getDirectoryTree()->currentDirectory();
|
||||||
|
if (dir) {
|
||||||
|
QString msg(tr("Search current folder %1.").arg(dir->getName()));
|
||||||
|
appendLogLine(msg);
|
||||||
|
showMessage(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
result = m_search.search(dir);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case VSearchConfig::CurrentNotebook:
|
||||||
|
{
|
||||||
|
QVector<VNotebook *> notebooks;
|
||||||
|
notebooks.append(g_mainWin->getNotebookSelector()->currentNotebook());
|
||||||
|
if (notebooks[0]) {
|
||||||
|
QString msg(tr("Search current notebook %1.").arg(notebooks[0]->getName()));
|
||||||
|
appendLogLine(msg);
|
||||||
|
showMessage(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
result = m_search.search(notebooks);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case VSearchConfig::AllNotebooks:
|
||||||
|
{
|
||||||
|
const QVector<VNotebook *> ¬ebooks = g_vnote->getNotebooks();
|
||||||
|
result = m_search.search(notebooks);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
handleSearchFinished(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VSearcher::handleSearchFinished(const QSharedPointer<VSearchResult> &p_result)
|
||||||
|
{
|
||||||
|
Q_ASSERT(m_inSearch);
|
||||||
|
Q_ASSERT(p_result->m_state != VSearchState::Idle);
|
||||||
|
|
||||||
|
qDebug() << "handleSearchFinished" << (int)p_result->m_state;
|
||||||
|
|
||||||
|
QString msg;
|
||||||
|
switch (p_result->m_state) {
|
||||||
|
case VSearchState::Busy:
|
||||||
|
msg = tr("Search is on going.");
|
||||||
|
appendLogLine(msg);
|
||||||
|
return;
|
||||||
|
|
||||||
|
case VSearchState::Success:
|
||||||
|
msg = tr("Search succeeded.");
|
||||||
|
appendLogLine(msg);
|
||||||
|
showMessage(msg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VSearchState::Fail:
|
||||||
|
msg = tr("Search failed.");
|
||||||
|
appendLogLine(msg);
|
||||||
|
showMessage(msg);
|
||||||
|
VUtils::showMessage(QMessageBox::Warning,
|
||||||
|
tr("Warning"),
|
||||||
|
tr("Search failed."),
|
||||||
|
p_result->m_errMsg,
|
||||||
|
QMessageBox::Ok,
|
||||||
|
QMessageBox::Ok,
|
||||||
|
this);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VSearchState::Cancelled:
|
||||||
|
Q_ASSERT(m_askedToStop);
|
||||||
|
msg = tr("User cancelled the search. Aborted!");
|
||||||
|
appendLogLine(msg);
|
||||||
|
showMessage(msg);
|
||||||
|
m_askedToStop = false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p_result->m_state != VSearchState::Fail
|
||||||
|
&& p_result->hasError()) {
|
||||||
|
VUtils::showMessage(QMessageBox::Warning,
|
||||||
|
tr("Warning"),
|
||||||
|
tr("Errors found during search."),
|
||||||
|
p_result->m_errMsg,
|
||||||
|
QMessageBox::Ok,
|
||||||
|
QMessageBox::Ok,
|
||||||
|
this);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_search.clear();
|
||||||
|
|
||||||
|
m_inSearch = false;
|
||||||
|
m_searchBtn->setEnabled(true);
|
||||||
|
setProgressVisible(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VSearcher::animateSearchClick()
|
||||||
|
{
|
||||||
|
m_searchBtn->animateClick();
|
||||||
|
}
|
||||||
|
|
||||||
|
int VSearcher::getSearchOption() const
|
||||||
|
{
|
||||||
|
int ret = VSearchConfig::NoneOption;
|
||||||
|
|
||||||
|
if (m_caseSensitiveCB->isChecked()) {
|
||||||
|
ret |= VSearchConfig::CaseSensitive;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_wholeWordOnlyCB->isChecked()) {
|
||||||
|
ret |= VSearchConfig::WholeWordOnly;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_fuzzyCB->isChecked()) {
|
||||||
|
ret |= VSearchConfig::Fuzzy;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_regularExpressionCB->isChecked()) {
|
||||||
|
ret |= VSearchConfig::RegularExpression;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VSearcher::updateNumLabel(int p_count)
|
||||||
|
{
|
||||||
|
m_numLabel->setText(tr("%1 Items").arg(p_count));
|
||||||
|
}
|
||||||
|
|
||||||
|
void VSearcher::focusToSearch()
|
||||||
|
{
|
||||||
|
m_keywordCB->setFocus(Qt::OtherFocusReason);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VSearcher::showNavigation()
|
||||||
|
{
|
||||||
|
VNavigationMode::showNavigation(m_results);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VSearcher::handleKeyNavigation(int p_key, bool &p_succeed)
|
||||||
|
{
|
||||||
|
static bool secondKey = false;
|
||||||
|
return VNavigationMode::handleKeyNavigation(m_results,
|
||||||
|
secondKey,
|
||||||
|
p_key,
|
||||||
|
p_succeed);
|
||||||
|
}
|
108
src/vsearcher.h
Normal file
108
src/vsearcher.h
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
#ifndef VSEARCHER_H
|
||||||
|
#define VSEARCHER_H
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QSharedPointer>
|
||||||
|
|
||||||
|
#include "vsearch.h"
|
||||||
|
|
||||||
|
#include "vnavigationmode.h"
|
||||||
|
|
||||||
|
class QComboBox;
|
||||||
|
class QCheckBox;
|
||||||
|
class QPushButton;
|
||||||
|
class QLabel;
|
||||||
|
class VSearchResultTree;
|
||||||
|
class QProgressBar;
|
||||||
|
class QPlainTextEdit;
|
||||||
|
|
||||||
|
class VSearcher : public QWidget, public VNavigationMode
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit VSearcher(QWidget *p_parent = nullptr);
|
||||||
|
|
||||||
|
void focusToSearch();
|
||||||
|
|
||||||
|
// Implementations for VNavigationMode.
|
||||||
|
void showNavigation() Q_DECL_OVERRIDE;
|
||||||
|
bool handleKeyNavigation(int p_key, bool &p_succeed) Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void handleSearchFinished(const QSharedPointer<VSearchResult> &p_result);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void startSearch();
|
||||||
|
|
||||||
|
void setupUI();
|
||||||
|
|
||||||
|
void initUIFields();
|
||||||
|
|
||||||
|
void setProgressVisible(bool p_visible);
|
||||||
|
|
||||||
|
void appendLogLine(const QString &p_text);
|
||||||
|
|
||||||
|
void handleInputChanged();
|
||||||
|
|
||||||
|
void animateSearchClick();
|
||||||
|
|
||||||
|
void updateItemToComboBox(QComboBox *p_comboBox);
|
||||||
|
|
||||||
|
// Get the OR of the search options.
|
||||||
|
int getSearchOption() const;
|
||||||
|
|
||||||
|
void updateNumLabel(int p_count);
|
||||||
|
|
||||||
|
void showMessage(const QString &p_text) const;
|
||||||
|
|
||||||
|
QComboBox *m_keywordCB;
|
||||||
|
|
||||||
|
// All notebooks, current notebook, and so on.
|
||||||
|
QComboBox *m_searchScopeCB;
|
||||||
|
|
||||||
|
// Name, content, tag.
|
||||||
|
QComboBox *m_searchObjectCB;
|
||||||
|
|
||||||
|
// Notebook, folder, note.
|
||||||
|
QComboBox *m_searchTargetCB;
|
||||||
|
|
||||||
|
QComboBox *m_filePatternCB;
|
||||||
|
|
||||||
|
QComboBox *m_searchEngineCB;
|
||||||
|
|
||||||
|
QCheckBox *m_caseSensitiveCB;
|
||||||
|
|
||||||
|
QCheckBox *m_wholeWordOnlyCB;
|
||||||
|
|
||||||
|
QCheckBox *m_fuzzyCB;
|
||||||
|
|
||||||
|
QCheckBox *m_regularExpressionCB;
|
||||||
|
|
||||||
|
QPushButton *m_searchBtn;
|
||||||
|
|
||||||
|
QPushButton *m_clearBtn;
|
||||||
|
|
||||||
|
QPushButton *m_advBtn;
|
||||||
|
|
||||||
|
QPushButton *m_consoleBtn;
|
||||||
|
|
||||||
|
QLabel *m_numLabel;
|
||||||
|
|
||||||
|
QWidget *m_advWidget;
|
||||||
|
|
||||||
|
VSearchResultTree *m_results;
|
||||||
|
|
||||||
|
QProgressBar *m_proBar;
|
||||||
|
|
||||||
|
QPushButton *m_cancelBtn;
|
||||||
|
|
||||||
|
QPlainTextEdit *m_consoleEdit;
|
||||||
|
|
||||||
|
bool m_inSearch;
|
||||||
|
|
||||||
|
bool m_askedToStop;
|
||||||
|
|
||||||
|
VSearch m_search;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // VSEARCHER_H
|
143
src/vsearchresulttree.cpp
Normal file
143
src/vsearchresulttree.cpp
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
#include "vsearchresulttree.h"
|
||||||
|
|
||||||
|
#include "utils/viconutils.h"
|
||||||
|
#include "vnote.h"
|
||||||
|
#include "vmainwindow.h"
|
||||||
|
#include "vnotebookselector.h"
|
||||||
|
|
||||||
|
extern VNote *g_vnote;
|
||||||
|
|
||||||
|
extern VMainWindow *g_mainWin;
|
||||||
|
|
||||||
|
VSearchResultTree::VSearchResultTree(QWidget *p_parent)
|
||||||
|
: VTreeWidget(p_parent)
|
||||||
|
{
|
||||||
|
setColumnCount(1);
|
||||||
|
setHeaderHidden(true);
|
||||||
|
setExpandsOnDoubleClick(false);
|
||||||
|
|
||||||
|
setSimpleSearchMatchFlags(getSimpleSearchMatchFlags() & ~Qt::MatchRecursive);
|
||||||
|
|
||||||
|
m_noteIcon = VIconUtils::treeViewIcon(":/resources/icons/note_item.svg");
|
||||||
|
m_folderIcon = VIconUtils::treeViewIcon(":/resources/icons/dir_item.svg");
|
||||||
|
m_notebookIcon = VIconUtils::treeViewIcon(":/resources/icons/notebook_item.svg");
|
||||||
|
|
||||||
|
connect(this, &VTreeWidget::itemActivated,
|
||||||
|
this, &VSearchResultTree::handleItemActivated);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VSearchResultTree::updateResults(const QList<QSharedPointer<VSearchResultItem> > &p_items)
|
||||||
|
{
|
||||||
|
clearResults();
|
||||||
|
|
||||||
|
for (auto const & it : p_items) {
|
||||||
|
appendItem(it);
|
||||||
|
}
|
||||||
|
|
||||||
|
emit countChanged(topLevelItemCount());
|
||||||
|
}
|
||||||
|
|
||||||
|
void VSearchResultTree::addResultItem(const QSharedPointer<VSearchResultItem> &p_item)
|
||||||
|
{
|
||||||
|
appendItem(p_item);
|
||||||
|
|
||||||
|
emit countChanged(topLevelItemCount());
|
||||||
|
}
|
||||||
|
|
||||||
|
void VSearchResultTree::clearResults()
|
||||||
|
{
|
||||||
|
clearAll();
|
||||||
|
|
||||||
|
m_data.clear();
|
||||||
|
|
||||||
|
emit countChanged(topLevelItemCount());
|
||||||
|
}
|
||||||
|
|
||||||
|
void VSearchResultTree::appendItem(const QSharedPointer<VSearchResultItem> &p_item)
|
||||||
|
{
|
||||||
|
m_data.append(p_item);
|
||||||
|
|
||||||
|
QTreeWidgetItem *item = new QTreeWidgetItem(this);
|
||||||
|
item->setData(0, Qt::UserRole, m_data.size() - 1);
|
||||||
|
item->setText(0, p_item->m_text.isEmpty() ? p_item->m_path : p_item->m_text);
|
||||||
|
item->setToolTip(0, p_item->m_path);
|
||||||
|
|
||||||
|
switch (p_item->m_type) {
|
||||||
|
case VSearchResultItem::Note:
|
||||||
|
item->setIcon(0, m_noteIcon);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VSearchResultItem::Folder:
|
||||||
|
item->setIcon(0, m_folderIcon);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VSearchResultItem::Notebook:
|
||||||
|
item->setIcon(0, m_notebookIcon);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto const & it: p_item->m_matches) {
|
||||||
|
QTreeWidgetItem *subItem = new QTreeWidgetItem(item);
|
||||||
|
QString text;
|
||||||
|
if (it.m_lineNumber > -1) {
|
||||||
|
text = QString("[%1] %2").arg(it.m_lineNumber).arg(it.m_text);
|
||||||
|
} else {
|
||||||
|
text = it.m_text;
|
||||||
|
}
|
||||||
|
|
||||||
|
subItem->setText(0, text);
|
||||||
|
subItem->setToolTip(0, it.m_text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VSearchResultTree::handleItemActivated(QTreeWidgetItem *p_item, int p_column)
|
||||||
|
{
|
||||||
|
Q_UNUSED(p_column);
|
||||||
|
if (!p_item) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QTreeWidgetItem *topItem = p_item;
|
||||||
|
if (p_item->parent()) {
|
||||||
|
topItem = p_item->parent();
|
||||||
|
}
|
||||||
|
|
||||||
|
int idx = topItem->data(0, Qt::UserRole).toInt();
|
||||||
|
Q_ASSERT(idx >= 0 && idx < m_data.size());
|
||||||
|
|
||||||
|
const QSharedPointer<VSearchResultItem> &resItem = m_data[idx];
|
||||||
|
switch (resItem->m_type) {
|
||||||
|
case VSearchResultItem::Note:
|
||||||
|
{
|
||||||
|
QStringList files(resItem->m_path);
|
||||||
|
g_mainWin->openFiles(files);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case VSearchResultItem::Folder:
|
||||||
|
{
|
||||||
|
VDirectory *dir = g_vnote->getInternalDirectory(resItem->m_path);
|
||||||
|
if (dir) {
|
||||||
|
g_mainWin->locateDirectory(dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case VSearchResultItem::Notebook:
|
||||||
|
{
|
||||||
|
VNotebook *nb = g_vnote->getNotebook(resItem->m_path);
|
||||||
|
if (nb) {
|
||||||
|
g_mainWin->getNotebookSelector()->locateNotebook(nb);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
39
src/vsearchresulttree.h
Normal file
39
src/vsearchresulttree.h
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
#ifndef VSEARCHRESULTTREE_H
|
||||||
|
#define VSEARCHRESULTTREE_H
|
||||||
|
|
||||||
|
#include <QIcon>
|
||||||
|
|
||||||
|
#include "vtreewidget.h"
|
||||||
|
#include "vsearch.h"
|
||||||
|
|
||||||
|
|
||||||
|
class VSearchResultTree : public VTreeWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit VSearchResultTree(QWidget *p_parent = nullptr);
|
||||||
|
|
||||||
|
void updateResults(const QList<QSharedPointer<VSearchResultItem> > &p_items);
|
||||||
|
|
||||||
|
void clearResults();
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void addResultItem(const QSharedPointer<VSearchResultItem> &p_item);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void countChanged(int p_count);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void handleItemActivated(QTreeWidgetItem *p_item, int p_column);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void appendItem(const QSharedPointer<VSearchResultItem> &p_item);
|
||||||
|
|
||||||
|
QVector<QSharedPointer<VSearchResultItem> > m_data;
|
||||||
|
|
||||||
|
QIcon m_noteIcon;
|
||||||
|
QIcon m_folderIcon;
|
||||||
|
QIcon m_notebookIcon;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // VSEARCHRESULTTREE_H
|
@ -47,6 +47,10 @@ public:
|
|||||||
|
|
||||||
void setNavigationKeyEnabled(bool p_enabled);
|
void setNavigationKeyEnabled(bool p_enabled);
|
||||||
|
|
||||||
|
void setMatchFlags(Qt::MatchFlags p_flags);
|
||||||
|
|
||||||
|
Qt::MatchFlags getMatchFlags() const;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
// Search mode is triggered.
|
// Search mode is triggered.
|
||||||
void triggered(bool p_inSearchMode);
|
void triggered(bool p_inSearchMode);
|
||||||
@ -101,4 +105,14 @@ inline void VSimpleSearchInput::setNavigationKeyEnabled(bool p_enabled)
|
|||||||
{
|
{
|
||||||
m_navigationKeyEnabled = p_enabled;
|
m_navigationKeyEnabled = p_enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void VSimpleSearchInput::setMatchFlags(Qt::MatchFlags p_flags)
|
||||||
|
{
|
||||||
|
m_matchFlags = p_flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Qt::MatchFlags VSimpleSearchInput::getMatchFlags() const
|
||||||
|
{
|
||||||
|
return m_matchFlags;
|
||||||
|
}
|
||||||
#endif // VSIMPLESEARCHINPUT_H
|
#endif // VSIMPLESEARCHINPUT_H
|
||||||
|
@ -43,6 +43,8 @@ void VTextEdit::init()
|
|||||||
{
|
{
|
||||||
setAcceptRichText(false);
|
setAcceptRichText(false);
|
||||||
|
|
||||||
|
m_defaultCursorWidth = 1;
|
||||||
|
|
||||||
m_lineNumberType = LineNumberType::None;
|
m_lineNumberType = LineNumberType::None;
|
||||||
|
|
||||||
m_blockImageEnabled = false;
|
m_blockImageEnabled = false;
|
||||||
@ -60,6 +62,8 @@ void VTextEdit::init()
|
|||||||
|
|
||||||
docLayout->setVirtualCursorBlockWidth(VIRTUAL_CURSOR_BLOCK_WIDTH);
|
docLayout->setVirtualCursorBlockWidth(VIRTUAL_CURSOR_BLOCK_WIDTH);
|
||||||
|
|
||||||
|
docLayout->setCursorWidth(m_defaultCursorWidth);
|
||||||
|
|
||||||
connect(docLayout, &VTextDocumentLayout::cursorBlockWidthUpdated,
|
connect(docLayout, &VTextDocumentLayout::cursorBlockWidthUpdated,
|
||||||
this, [this](int p_width) {
|
this, [this](int p_width) {
|
||||||
if (p_width != cursorWidth()
|
if (p_width != cursorWidth()
|
||||||
@ -361,7 +365,7 @@ void VTextEdit::setCursorBlockMode(CursorBlock p_mode)
|
|||||||
layout->setCursorBlockMode(m_cursorBlockMode);
|
layout->setCursorBlockMode(m_cursorBlockMode);
|
||||||
layout->clearLastCursorBlockWidth();
|
layout->clearLastCursorBlockWidth();
|
||||||
setCursorWidth(m_cursorBlockMode != CursorBlock::None ? VIRTUAL_CURSOR_BLOCK_WIDTH
|
setCursorWidth(m_cursorBlockMode != CursorBlock::None ? VIRTUAL_CURSOR_BLOCK_WIDTH
|
||||||
: 1);
|
: m_defaultCursorWidth);
|
||||||
layout->updateBlockByNumber(textCursor().blockNumber());
|
layout->updateBlockByNumber(textCursor().blockNumber());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -388,3 +392,12 @@ void VTextEdit::relayout()
|
|||||||
{
|
{
|
||||||
getLayout()->relayout();
|
getLayout()->relayout();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VTextEdit::setDisplayScaleFactor(qreal p_factor)
|
||||||
|
{
|
||||||
|
m_defaultCursorWidth = p_factor + 0.5;
|
||||||
|
|
||||||
|
setCursorWidth(m_cursorBlockMode != CursorBlock::None ? VIRTUAL_CURSOR_BLOCK_WIDTH
|
||||||
|
: m_defaultCursorWidth);
|
||||||
|
getLayout()->setCursorWidth(m_defaultCursorWidth);
|
||||||
|
}
|
||||||
|
@ -65,6 +65,8 @@ public:
|
|||||||
|
|
||||||
void relayout();
|
void relayout();
|
||||||
|
|
||||||
|
void setDisplayScaleFactor(qreal p_factor);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void resizeEvent(QResizeEvent *p_event) Q_DECL_OVERRIDE;
|
void resizeEvent(QResizeEvent *p_event) Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
@ -91,6 +93,8 @@ private:
|
|||||||
CursorBlock m_cursorBlockMode;
|
CursorBlock m_cursorBlockMode;
|
||||||
|
|
||||||
bool m_highlightCursorLineBlock;
|
bool m_highlightCursorLineBlock;
|
||||||
|
|
||||||
|
int m_defaultCursorWidth;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline void VTextEdit::setLineNumberType(LineNumberType p_type)
|
inline void VTextEdit::setLineNumberType(LineNumberType p_type)
|
||||||
|
@ -21,6 +21,10 @@ public:
|
|||||||
// Clear tree widget as well as other data.
|
// Clear tree widget as well as other data.
|
||||||
void clearAll();
|
void clearAll();
|
||||||
|
|
||||||
|
void setSimpleSearchMatchFlags(Qt::MatchFlags p_flags);
|
||||||
|
|
||||||
|
Qt::MatchFlags getSimpleSearchMatchFlags() const;
|
||||||
|
|
||||||
// Implement ISimpleSearch.
|
// Implement ISimpleSearch.
|
||||||
virtual QList<void *> searchItems(const QString &p_text,
|
virtual QList<void *> searchItems(const QString &p_text,
|
||||||
Qt::MatchFlags p_flags) const Q_DECL_OVERRIDE;
|
Qt::MatchFlags p_flags) const Q_DECL_OVERRIDE;
|
||||||
@ -65,4 +69,14 @@ private:
|
|||||||
|
|
||||||
QTimer *m_searchColdTimer;
|
QTimer *m_searchColdTimer;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline void VTreeWidget::setSimpleSearchMatchFlags(Qt::MatchFlags p_flags)
|
||||||
|
{
|
||||||
|
m_searchInput->setMatchFlags(p_flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Qt::MatchFlags VTreeWidget::getSimpleSearchMatchFlags() const
|
||||||
|
{
|
||||||
|
return m_searchInput->getMatchFlags();
|
||||||
|
}
|
||||||
#endif // VTREEWIDGET_H
|
#endif // VTREEWIDGET_H
|
||||||
|
Loading…
x
Reference in New Issue
Block a user