summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--components/mailviewer/qml/HtmlContent.qml5
-rw-r--r--components/mailviewer/qml/MailDataModel.qml8
-rw-r--r--components/mailviewer/qml/MailViewer.qml1
-rw-r--r--components/mailviewer/qml/TextContent.qml10
-rw-r--r--framework/qml/ConversationView.qml8
-rw-r--r--framework/qml/MailListView.qml4
-rw-r--r--framework/qml/MailViewer.qml1
-rw-r--r--framework/qml/Messages.qml1
-rw-r--r--framework/src/CMakeLists.txt4
-rw-r--r--framework/src/frameworkplugin.cpp2
-rw-r--r--framework/src/viewhighlighter.cpp91
-rw-r--r--framework/src/viewhighlighter.h40
-rw-r--r--views/conversation/main.qml14
13 files changed, 187 insertions, 2 deletions
diff --git a/components/mailviewer/qml/HtmlContent.qml b/components/mailviewer/qml/HtmlContent.qml
index f0249a01..c775a3ca 100644
--- a/components/mailviewer/qml/HtmlContent.qml
+++ b/components/mailviewer/qml/HtmlContent.qml
@@ -27,7 +27,10 @@ Item {
27 property string content 27 property string content
28 //We have to give it a minimum size so the html content starts to expand 28 //We have to give it a minimum size so the html content starts to expand
29 property int contentHeight: 10; 29 property int contentHeight: 10;
30 30 property string searchString
31 onSearchStringChanged: {
32 htmlView.findText(searchString)
33 }
31 34
32 WebEngineView { 35 WebEngineView {
33 id: htmlView 36 id: htmlView
diff --git a/components/mailviewer/qml/MailDataModel.qml b/components/mailviewer/qml/MailDataModel.qml
index d960b2ac..fdc3ce22 100644
--- a/components/mailviewer/qml/MailDataModel.qml
+++ b/components/mailviewer/qml/MailDataModel.qml
@@ -23,6 +23,8 @@ import org.kube.framework 1.0 as Kube
23DelegateModel { 23DelegateModel {
24 id: root 24 id: root
25 25
26 property string searchString: ""
27
26 delegate: Item { 28 delegate: Item {
27 id: partColumn 29 id: partColumn
28 30
@@ -124,6 +126,12 @@ DelegateModel {
124 } 126 }
125 height: item ? item.contentHeight : 0 127 height: item ? item.contentHeight : 0
126 width: parent.width 128 width: parent.width
129 Binding {
130 target: partLoader.item
131 property: "searchString"
132 value: root.searchString
133 when: partLoader.status == Loader.Ready
134 }
127 } 135 }
128 Component.onCompleted: { 136 Component.onCompleted: {
129 switch (model.type) { 137 switch (model.type) {
diff --git a/components/mailviewer/qml/MailViewer.qml b/components/mailviewer/qml/MailViewer.qml
index 9031ec17..faf3bc61 100644
--- a/components/mailviewer/qml/MailViewer.qml
+++ b/components/mailviewer/qml/MailViewer.qml
@@ -22,6 +22,7 @@ Item {
22 id: root 22 id: root
23 property alias rootIndex: visualModel.rootIndex 23 property alias rootIndex: visualModel.rootIndex
24 property alias model: visualModel.model 24 property alias model: visualModel.model
25 property alias searchString: visualModel.searchString
25 height: partListView.height 26 height: partListView.height
26 27
27 MailDataModel { 28 MailDataModel {
diff --git a/components/mailviewer/qml/TextContent.qml b/components/mailviewer/qml/TextContent.qml
index 316786ef..95e196b4 100644
--- a/components/mailviewer/qml/TextContent.qml
+++ b/components/mailviewer/qml/TextContent.qml
@@ -27,8 +27,14 @@ Item {
27 property bool embedded: true 27 property bool embedded: true
28 property string type 28 property string type
29 29
30 property string searchString
30 property int contentHeight: textEdit.height 31 property int contentHeight: textEdit.height
31 32
33 onSearchStringChanged: {
34 //This is a workaround because otherwise the view will not take the ViewHighlighter changes into account.
35 textEdit.text = root.content
36 }
37
32 TextEdit { 38 TextEdit {
33 id: textEdit 39 id: textEdit
34 40
@@ -56,5 +62,9 @@ Item {
56 acceptedButtons: Qt.NoButton // we don't want to eat clicks on the Text 62 acceptedButtons: Qt.NoButton // we don't want to eat clicks on the Text
57 cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor 63 cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor
58 } 64 }
65 Kube.ViewHighlighter {
66 textDocument: textEdit.textDocument
67 searchString: root.searchString
68 }
59 } 69 }
60} 70}
diff --git a/framework/qml/ConversationView.qml b/framework/qml/ConversationView.qml
index 2dab92ba..0fd76f8f 100644
--- a/framework/qml/ConversationView.qml
+++ b/framework/qml/ConversationView.qml
@@ -31,6 +31,12 @@ FocusScope {
31 property variant mail; 31 property variant mail;
32 property bool hideTrash: true; 32 property bool hideTrash: true;
33 property bool hideNonTrash: false; 33 property bool hideNonTrash: false;
34 property string searchString: ""
35
36 Kube.Listener {
37 filter: Kube.Messages.searchString
38 onMessageReceived: root.searchString = message.searchString
39 }
34 40
35 Rectangle { 41 Rectangle {
36 anchors.fill: parent 42 anchors.fill: parent
@@ -46,6 +52,7 @@ FocusScope {
46 left: parent.left 52 left: parent.left
47 right: parent.right 53 right: parent.right
48 } 54 }
55
49 //Shrink the listview if the content doesn't fill the full height, so the email appears on top instead of on the bottom. 56 //Shrink the listview if the content doesn't fill the full height, so the email appears on top instead of on the bottom.
50 height: Math.min(contentHeight, parent.height) 57 height: Math.min(contentHeight, parent.height)
51 58
@@ -98,6 +105,7 @@ FocusScope {
98 sent: model.sent 105 sent: model.sent
99 incomplete: model.incomplete 106 incomplete: model.incomplete
100 current: delegateRoot.isCurrentItem 107 current: delegateRoot.isCurrentItem
108 searchString: root.searchString
101 } 109 }
102 } 110 }
103 111
diff --git a/framework/qml/MailListView.qml b/framework/qml/MailListView.qml
index 35c90618..cc68f003 100644
--- a/framework/qml/MailListView.qml
+++ b/framework/qml/MailListView.qml
@@ -35,6 +35,10 @@ FocusScope {
35 property bool showFilter: false 35 property bool showFilter: false
36 property string filter: null 36 property string filter: null
37 37
38 onFilterChanged: {
39 Kube.Fabric.postMessage(Kube.Messages.searchString, {"searchString": filter})
40 }
41
38 onParentFolderChanged: { 42 onParentFolderChanged: {
39 currentMail = null 43 currentMail = null
40 filterField.clearSearch() 44 filterField.clearSearch()
diff --git a/framework/qml/MailViewer.qml b/framework/qml/MailViewer.qml
index f52e694d..e37fb3f7 100644
--- a/framework/qml/MailViewer.qml
+++ b/framework/qml/MailViewer.qml
@@ -42,6 +42,7 @@ Rectangle {
42 property bool incomplete: false; 42 property bool incomplete: false;
43 property bool current: false; 43 property bool current: false;
44 property bool unread; 44 property bool unread;
45 property alias searchString: mailViewer.searchString
45 46
46 implicitHeight: header.height + attachments.height + body.height + incompleteBody.height + footer.height + Kube.Units.largeSpacing 47 implicitHeight: header.height + attachments.height + body.height + incompleteBody.height + footer.height + Kube.Units.largeSpacing
47 48
diff --git a/framework/qml/Messages.qml b/framework/qml/Messages.qml
index 9df83863..35aa750a 100644
--- a/framework/qml/Messages.qml
+++ b/framework/qml/Messages.qml
@@ -42,6 +42,7 @@ Item {
42 property string progressNotification: "progressNotification" 42 property string progressNotification: "progressNotification"
43 property string errorNotification: "errorNotification" 43 property string errorNotification: "errorNotification"
44 property string search: "search" 44 property string search: "search"
45 property string searchString: "searchString"
45 property string synchronize: "synchronize" 46 property string synchronize: "synchronize"
46 property string reply: "reply" 47 property string reply: "reply"
47 property string forward: "forward" 48 property string forward: "forward"
diff --git a/framework/src/CMakeLists.txt b/framework/src/CMakeLists.txt
index 97cb453b..f11e6077 100644
--- a/framework/src/CMakeLists.txt
+++ b/framework/src/CMakeLists.txt
@@ -1,5 +1,5 @@
1 1
2find_package(Qt5 COMPONENTS REQUIRED Core Concurrent Quick Qml WebEngineWidgets Test WebEngine) 2find_package(Qt5 COMPONENTS REQUIRED Core Concurrent Quick Qml WebEngineWidgets Test WebEngine Gui)
3find_package(KF5Mime "4.87.0" CONFIG REQUIRED) 3find_package(KF5Mime "4.87.0" CONFIG REQUIRED)
4find_package(Sink CONFIG REQUIRED) 4find_package(Sink CONFIG REQUIRED)
5find_package(KAsync CONFIG REQUIRED) 5find_package(KAsync CONFIG REQUIRED)
@@ -48,6 +48,7 @@ add_library(kubeframework SHARED
48 keyring.cpp 48 keyring.cpp
49 domainobjectcontroller.cpp 49 domainobjectcontroller.cpp
50 extensionmodel.cpp 50 extensionmodel.cpp
51 viewhighlighter.cpp
51 ) 52 )
52target_link_libraries(kubeframework 53target_link_libraries(kubeframework
53 sink 54 sink
@@ -58,6 +59,7 @@ target_link_libraries(kubeframework
58 Qt5::WebEngineWidgets 59 Qt5::WebEngineWidgets
59 Qt5::Test 60 Qt5::Test
60 Qt5::WebEngine 61 Qt5::WebEngine
62 Qt5::Gui
61 KF5::Codecs 63 KF5::Codecs
62 KF5::Contacts 64 KF5::Contacts
63 KAsync 65 KAsync
diff --git a/framework/src/frameworkplugin.cpp b/framework/src/frameworkplugin.cpp
index b0e2f9c9..d512ce10 100644
--- a/framework/src/frameworkplugin.cpp
+++ b/framework/src/frameworkplugin.cpp
@@ -42,6 +42,7 @@
42#include "controller.h" 42#include "controller.h"
43#include "domainobjectcontroller.h" 43#include "domainobjectcontroller.h"
44#include "extensionmodel.h" 44#include "extensionmodel.h"
45#include "viewhighlighter.h"
45 46
46#include <QtQml> 47#include <QtQml>
47#include <QQuickImageProvider> 48#include <QQuickImageProvider>
@@ -142,6 +143,7 @@ void FrameworkPlugin::registerTypes (const char *uri)
142 qmlRegisterType<KubeImage>(uri, 1, 0, "KubeImage"); 143 qmlRegisterType<KubeImage>(uri, 1, 0, "KubeImage");
143 qmlRegisterType<ClipboardProxy>(uri, 1, 0, "Clipboard"); 144 qmlRegisterType<ClipboardProxy>(uri, 1, 0, "Clipboard");
144 qmlRegisterType<StartupCheck>(uri, 1, 0, "StartupCheck"); 145 qmlRegisterType<StartupCheck>(uri, 1, 0, "StartupCheck");
146 qmlRegisterType<ViewHighlighter>(uri, 1, 0, "ViewHighlighter");
145 qmlRegisterSingletonType<WebEngineProfile>(uri, 1, 0, "WebEngineProfile", webengineprofile_singletontype_provider); 147 qmlRegisterSingletonType<WebEngineProfile>(uri, 1, 0, "WebEngineProfile", webengineprofile_singletontype_provider);
146 qmlRegisterSingletonType<Kube::Keyring>(uri, 1, 0, "Keyring", keyring_singletontype_provider); 148 qmlRegisterSingletonType<Kube::Keyring>(uri, 1, 0, "Keyring", keyring_singletontype_provider);
147} 149}
diff --git a/framework/src/viewhighlighter.cpp b/framework/src/viewhighlighter.cpp
new file mode 100644
index 00000000..553646f2
--- /dev/null
+++ b/framework/src/viewhighlighter.cpp
@@ -0,0 +1,91 @@
1/*
2 Copyright (c) 2018 Christian Mollekopf <mollekopf@kolabsys.com>
3
4 This library is free software; you can redistribute it and/or modify it
5 under the terms of the GNU Library General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or (at your
7 option) any later version.
8
9 This library is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
12 License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to the
16 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 02110-1301, USA.
18*/
19#include "viewhighlighter.h"
20
21#include <QQuickTextDocument>
22#include <QSyntaxHighlighter>
23#include <QRegularExpression>
24#include <QString>
25
26class SearchHighlighter : public QSyntaxHighlighter
27{
28 Q_OBJECT
29
30public:
31 SearchHighlighter(QTextDocument *parent = 0)
32 : QSyntaxHighlighter(parent)
33 {
34 }
35
36 void setSearchString(const QString &s)
37 {
38 mSearchString = s;
39 rehighlight();
40 }
41
42protected:
43 void highlightBlock(const QString &text) override
44 {
45 if (!mSearchString.isEmpty()) {
46 QTextCharFormat format;
47 format.setFontWeight(QFont::Bold);
48 format.setBackground(QColor{"#f67400"});
49
50 QRegularExpression expression(mSearchString, QRegularExpression::CaseInsensitiveOption);
51 auto i = expression.globalMatch(text);
52 while (i.hasNext()) {
53 auto match = i.next();
54 setFormat(match.capturedStart(), match.capturedLength(), format);
55 }
56 }
57
58 }
59
60private:
61 QString mSearchString;
62};
63
64struct ViewHighlighter::Private {
65 SearchHighlighter *searchHighligher;
66
67};
68
69
70ViewHighlighter::ViewHighlighter(QObject *parent)
71 : QObject(parent),
72 d{new Private}
73{
74
75}
76
77void ViewHighlighter::setTextDocument(QQuickTextDocument *document)
78{
79 if (document) {
80 d->searchHighligher = new SearchHighlighter{document->textDocument()};
81 }
82}
83
84void ViewHighlighter::setSearchString(const QString &s)
85{
86 if (d->searchHighligher) {
87 d->searchHighligher->setSearchString(s);
88 }
89}
90
91#include "viewhighlighter.moc"
diff --git a/framework/src/viewhighlighter.h b/framework/src/viewhighlighter.h
new file mode 100644
index 00000000..00b4d4b6
--- /dev/null
+++ b/framework/src/viewhighlighter.h
@@ -0,0 +1,40 @@
1/*
2 Copyright (c) 2018 Christian Mollekopf <mollekopf@kolabsys.com>
3
4 This library is free software; you can redistribute it and/or modify it
5 under the terms of the GNU Library General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or (at your
7 option) any later version.
8
9 This library is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
12 License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to the
16 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 02110-1301, USA.
18*/
19
20#include <QObject>
21#include <QSharedPointer>
22
23class QQuickTextDocument;
24
25class ViewHighlighter : public QObject {
26 Q_OBJECT
27
28 Q_PROPERTY(QString searchString WRITE setSearchString)
29 Q_PROPERTY(QQuickTextDocument *textDocument WRITE setTextDocument CONSTANT)
30
31public:
32 ViewHighlighter(QObject *parent = nullptr);
33
34 void setTextDocument(QQuickTextDocument *);
35 void setSearchString(const QString& );
36
37private:
38 struct Private;
39 QSharedPointer<Private> d;
40};
diff --git a/views/conversation/main.qml b/views/conversation/main.qml
index 686aeecb..64f7f273 100644
--- a/views/conversation/main.qml
+++ b/views/conversation/main.qml
@@ -117,12 +117,26 @@ ApplicationWindow {
117 to: ["to@example.org"], 117 to: ["to@example.org"],
118 unread: true 118 unread: true
119 }, 119 },
120 {
121 resource: "resource1",
122 date: "2017-07-20T17:46:29",
123 subject: "ComplexHTMLLongLine",
124 //We assume that @media trigger the complex html view
125 body: "<pre>Hi Mélanie,\n\nI'm sorry @media to start this on such late notice, but we'd like to get Foo and boo to woo next week, because the following weeks are unfortunately not possible for us.\n<pre>",
126 bodyIsHtml: true,
127 to: ["to@example.org"],
128 unread: true
129 },
120 ] 130 ]
121 }], 131 }],
122 } 132 }
123 TestStore.setup(initialState) 133 TestStore.setup(initialState)
124 } 134 }
125 135
136 Shortcut {
137 onActivated: Kube.Fabric.postMessage(Kube.Messages.search, {})
138 sequence: StandardKey.Find
139 }
126 View { 140 View {
127 anchors.fill: parent 141 anchors.fill: parent
128 } 142 }