Browse Source

Replace QWebView with TypicaWebView for XML and script instantiations

Neal Wilson 11 years ago
parent
commit
924a2bb2ff
3 changed files with 197 additions and 134 deletions
  1. 4
    2
      src/Typica.pro
  2. 1
    132
      src/typica.w
  3. 192
    0
      src/webview.w

+ 4
- 2
src/Typica.pro View File

@@ -19,11 +19,13 @@ DEPENDPATH += .
19 19
 HEADERS += moc_typica.cpp \
20 20
     helpmenu.h \
21 21
     abouttypica.h \
22
-    units.h
22
+    units.h \
23
+    webview.h
23 24
 SOURCES += typica.cpp \
24 25
     helpmenu.cpp \
25 26
     abouttypica.cpp \
26
-    units.cpp
27
+    units.cpp \
28
+    webview.cpp
27 29
 
28 30
 RESOURCES += \
29 31
     resources.qrc

+ 1
- 132
src/typica.w View File

@@ -11576,138 +11576,7 @@ void CSVOutput::setDevice(QIODevice *device)
11576 11576
 	out = device;
11577 11577
 }
11578 11578
 
11579
-@* Web views.
11580
-
11581
-The |QWebView| class was initially brought in to handle printing roast profile
11582
-data. This works by transforming the roasting data to an XHTML+SVG document,
11583
-loading it into a web view, and calling the |print()| method on that. Support
11584
-has since been extended to make it easier to produce reports that require either
11585
-postprocessing database results or database capabilities that are not readily
11586
-available in the reporting framework.
11587
-
11588
-With this new use, future development should allow inclusion of a web view in
11589
-the user interface without needing to instantiate it from a script.
11590
-
11591
-@<Set up the scripting engine@>=
11592
-constructor = engine->newFunction(constructWebView);
11593
-value = engine->newQMetaObject(&QWebView::staticMetaObject, constructor);
11594
-engine->globalObject().setProperty("WebView", value);
11595
-
11596
-@ A few properties are required. These should be available regardless of how the
11597
-object was created.
11598
-
11599
-@<Functions for scripting@>=
11600
-QScriptValue constructWebView(QScriptContext *, QScriptEngine *engine)
11601
-{
11602
-	QScriptValue object = engine->newQObject(new QWebView());
11603
-	setQWebViewProperties(object, engine);
11604
-	return object;
11605
-}
11606
-
11607
-void setQWebViewProperties(QScriptValue value, QScriptEngine *engine)
11608
-{
11609
-	setQWidgetProperties(value, engine);
11610
-	value.setProperty("load", engine->newFunction(WebView_load));
11611
-	value.setProperty("print", engine->newFunction(WebView_print));
11612
-	value.setProperty("setHtml", engine->newFunction(WebView_setHtml));
11613
-	value.setProperty("setContent", engine->newFunction(WebView_setContent));
11614
-	value.setProperty("saveXml", engine->newFunction(WebView_saveXml));
11615
-}
11616
-
11617
-@ To get data into the web view, we load it from a URL passed in the form of a
11618
-string. This will usually be a local file, but it doesn't have to be.
11619
-
11620
-@<Functions for scripting@>=
11621
-QScriptValue WebView_load(QScriptContext *context, QScriptEngine *)
11622
-{
11623
-	QWebView *self = getself<QWebView *>(context);
11624
-	QString file = argument<QString>(0, context);
11625
-	self->load(QUrl(file));
11626
-	return QScriptValue();
11627
-}
11628
-
11629
-@ When wrapping |QWebView::print()|, we need to obtain a |QPrinter| which that
11630
-method expects. In order to set everything up properly, we display a standard
11631
-print dialog.
11632
-
11633
-@<Functions for scripting@>=
11634
-QScriptValue WebView_print(QScriptContext *context, QScriptEngine *)
11635
-{
11636
-	QWebView *self = getself<QWebView *>(context);
11637
-	QPrinter *printer = new QPrinter(QPrinter::HighResolution);
11638
-	QPrintDialog printDialog(printer, NULL);
11639
-	if(printDialog.exec() == QDialog::Accepted)
11640
-	{
11641
-		self->print(printer);
11642
-	}
11643
-	return QScriptValue();
11644
-}
11645
-
11646
-@ When wrapping |QWebView::setHtml()|, only the first argument containing the
11647
-content is required.
11648
-
11649
-@<Functions for scripting@>=
11650
-QScriptValue WebView_setHtml(QScriptContext *context, QScriptEngine *)
11651
-{
11652
-	QWebView *self = getself<QWebView *>(context);
11653
-	QString content = argument<QString>(0, context);
11654
-	self->setHtml(content);
11655
-	return QScriptValue();
11656
-}
11657
-
11658
-@ This is a simple wrapper around |QWebView::setContent()|, but it obtains its
11659
-argument from the data in a |QIODevice|. A MIME type of application/xhtml+xml is
11660
-specified by default to allow embedding SVG.
11661
-
11662
-@<Functions for scripting@>=
11663
-QScriptValue WebView_setContent(QScriptContext *context, QScriptEngine *)
11664
-{
11665
-	QWebView *self = getself<QWebView *>(context);
11666
-	QIODevice *device = argument<QIODevice *>(0, context);
11667
-	device->reset();
11668
-	QByteArray content = device->readAll();
11669
-	self->setContent(content, "application/xhtml+xml");
11670
-	return QScriptValue();
11671
-}
11672
-
11673
-@ It should be possible to save the XHTML documents generated for reports. The
11674
-saveXml property provides one way to do this.
11675
-
11676
-@<Functions for scripting@>=
11677
-QScriptValue WebView_saveXml(QScriptContext *context, QScriptEngine *)
11678
-{
11679
-	QWebView *self = getself<QWebView *>(context);
11680
-	return QScriptValue(self->page()->currentFrame()->documentElement().toOuterXml());
11681
-}
11682
-
11683
-@ The web view can be created from the XML portion of the configuration
11684
-document. This function adds the view to a box layout.
11685
-
11686
-@<Functions for scripting@>=
11687
-void addWebViewToLayout(QDomElement element, QStack<QWidget *> *,
11688
-                        QStack<QLayout *> *layoutStack)
11689
-{
11690
-	QWebView *view = new QWebView;
11691
-	if(element.hasAttribute("id"))
11692
-	{
11693
-		view->setObjectName(element.attribute("id"));
11694
-	}
11695
-	QBoxLayout *layout = qobject_cast<QBoxLayout *>(layoutStack->top());
11696
-	layout->addWidget(view);
11697
-}
11698
-
11699
-@ The function prototypes used above follow.
11700
-
11701
-@<Function prototypes for scripting@>=
11702
-QScriptValue constructWebView(QScriptContext *context, QScriptEngine *engine);
11703
-QScriptValue WebView_load(QScriptContext *context, QScriptEngine *engine);
11704
-QScriptValue WebView_print(QScriptContext *context, QScriptEngine *engine);
11705
-QScriptValue WebView_setContent(QScriptContext *context, QScriptEngine *engine);
11706
-QScriptValue WebView_setHtml(QScriptContext *context, QScriptEngine *engine);
11707
-QScriptValue WebView_saveXml(QScriptContext *context, QScriptEngine *);
11708
-void addWebViewToLayout(QDomElement element, QStack<QWidget *> *widgetStack,
11709
-                        QStack<QLayout *> *layoutStack);
11710
-void setQWebViewProperties(QScriptValue value, QScriptEngine *engine);
11579
+@i webview.w
11711 11580
 
11712 11581
 @* The Application class.
11713 11582
 

+ 192
- 0
src/webview.w View File

@@ -0,0 +1,192 @@
1
+@* Web Views in Typica.
2
+
3
+\noindent Typica makes extensive use of web views. All printing is currently
4
+handled by generating HTML with the required information, loading it into a web
5
+view, and using the print capabilities provided there. Reports are provided by
6
+running SQL queries, generating HTML, and displaying the results in a web view.
7
+Even the program'@q'@>s about window is primarily a web view.
8
+
9
+In order to simplify the implementation of certain features, we subclass
10
+|QWebView| and provide some additional functionality.
11
+
12
+@(webview.h@>=
13
+#include <QWebView>
14
+#include <QFile>
15
+#include <QMessageBox>
16
+#include <QDesktopServices>
17
+#include <QPrinter>
18
+#include <QPrintDialog>
19
+#include <QWebFrame>
20
+#include <QWebElement>
21
+
22
+#ifndef TypicaWebViewHeader
23
+#define TypicaWebViewHeader
24
+
25
+class TypicaWebView : public QWebView
26
+{
27
+	Q_OBJECT
28
+	public:
29
+		TypicaWebView();
30
+		Q_INVOKABLE void load(const QString &url);
31
+		Q_INVOKABLE void print();
32
+		Q_INVOKABLE void setHtml(const QString &html);
33
+		Q_INVOKABLE void setContent(QIODevice *device);
34
+		Q_INVOKABLE QString saveXml();
35
+	signals:
36
+		void scriptLinkClicked(const QString &link);
37
+	private slots:
38
+		void linkDelegate(const QUrl &url);
39
+};
40
+
41
+#endif
42
+
43
+@ The implementation is in a separate file.
44
+
45
+@(webview.cpp@>=
46
+#include "webview.h"
47
+
48
+@<TypicaWebView implementation@>@;
49
+
50
+@ In the constructor we set up our link delegation policy.
51
+
52
+@<TypicaWebView implementation@>=
53
+TypicaWebView::TypicaWebView() : QWebView()
54
+{
55
+	page()->setLinkDelegationPolicy(QWebPage::DelegateExternalLinks);
56
+	connect(page(), SIGNAL(linkClicked(QUrl)), this, SLOT(linkDelegate(QUrl)));
57
+}
58
+
59
+@ When a link is clicked, one of three things may happen. Certain reserved URLs
60
+will trigger an immediate event which is just handled internally without
61
+providing any kind of external notification. URLs that start with
62
+|"typica://script/"| will produce a signal containing the rest of the URL. This
63
+is intended for script code to intercept, interpret, and update the web view
64
+with the requested information. Everything else is passed to |QDesktopServices|
65
+which will defer to system-wide preferences for how to handle different link
66
+and file types.
67
+
68
+@<TypicaWebView implementation@>=
69
+void TypicaWebView::linkDelegate(const QUrl &url)
70
+{
71
+	if(url.scheme() == "typica")
72
+	{
73
+		QString address(url.toEncoded());
74
+		@<Detect and handle special links@>@;
75
+		@<Detect and handle script links@>@;
76
+	}
77
+	else
78
+	{
79
+		QDesktopServices::openUrl(url);
80
+	}
81
+}
82
+
83
+@ Currently the only special link is |"typica://aboutqt"| which brings up
84
+information about the Qt framework. This is used in the About Typica window.
85
+
86
+@<Detect and handle special links@>=
87
+if(address == "typica://aboutqt")
88
+{
89
+	QMessageBox::aboutQt(this);
90
+	return;
91
+}
92
+
93
+@ Script links split the link data to simplify interpretation in script code.
94
+
95
+@<Detect and handle script links@>=
96
+if(address.startsWith("typica://script/"))
97
+{
98
+	emit scriptLinkClicked(address.remove(0, 16));
99
+	return;
100
+}
101
+
102
+@ There is a limited set of functions that should be available to the host
103
+environment which are not declared as slots or otherwise have some missing
104
+functionality in the base class. In some cases the new functions can be
105
+distinguished by signature.
106
+
107
+@<TypicaWebView implementation@>=
108
+void TypicaWebView::load(const QString &url)
109
+{
110
+	QWebView::load(QUrl(url));
111
+}
112
+
113
+void TypicaWebView::print()
114
+{
115
+	QPrinter *printer = new QPrinter(QPrinter::HighResolution);
116
+	QPrintDialog printDialog(printer, NULL);
117
+	if(printDialog.exec() == QDialog::Accepted)
118
+	{
119
+		QWebView::print(printer);
120
+	}
121
+}
122
+
123
+void TypicaWebView::setHtml(const QString &html)
124
+{
125
+	QWebView::setHtml(html);
126
+}
127
+
128
+void TypicaWebView::setContent(QIODevice *device)
129
+{
130
+	device->reset();
131
+	QByteArray content = device->readAll();
132
+	QWebView::setContent(content, "application/xhtml+xml");
133
+}
134
+
135
+QString TypicaWebView::saveXml()
136
+{
137
+	return page()->currentFrame()->documentElement().toOuterXml();
138
+}
139
+
140
+@ Web views are exposed to the host environment in the usual manner.
141
+
142
+@<Set up the scripting engine@>=
143
+constructor = engine->newFunction(constructWebView);
144
+value = engine->newQMetaObject(&TypicaWebView::staticMetaObject, constructor);
145
+engine->globalObject().setProperty("WebView", value);
146
+
147
+@ Now that |QWebView| is subclassed, all of the features that we need should
148
+be available through the meta-object system automatically.
149
+
150
+@<Functions for scripting@>=
151
+QScriptValue constructWebView(QScriptContext *, QScriptEngine *engine)
152
+{
153
+	QScriptValue object = engine->newQObject(new TypicaWebView);
154
+	setQWebViewProperties(object, engine);
155
+	return object;
156
+}
157
+
158
+void setQWebViewProperties(QScriptValue value, QScriptEngine *engine)
159
+{
160
+	setQWidgetProperties(value, engine);
161
+}
162
+
163
+@ It is also possible to create these web views from the XML portion of the
164
+configuration document. A function is provided to add a new view to a box
165
+layout.
166
+
167
+@<Functions for scripting@>=
168
+void addWebViewToLayout(QDomElement element, QStack<QWidget *> *,
169
+                        QStack<QLayout *> *layoutStack)
170
+{
171
+	TypicaWebView *view = new TypicaWebView;
172
+	if(element.hasAttribute("id"))
173
+	{
174
+		view->setObjectName(element.attribute("id"));
175
+	}
176
+	QBoxLayout *layout = qobject_cast<QBoxLayout *>(layoutStack->top());
177
+	layout->addWidget(view);
178
+}
179
+
180
+@ Prototypes must be provided for these functions.
181
+
182
+@<Function prototypes for scripting@>=
183
+QScriptValue constructWebView(QScriptContext *context, QScriptEngine *engine);
184
+void setQWebViewProperties(QScriptValue value, QScriptEngine *engine);
185
+void addWebViewToLayout(QDomElement element, QStack<QWidget *> *widgetStack,
186
+                        QStack<QLayout *> *layoutStack);
187
+
188
+@ Finally, we must include our new header in |"typica.cpp"|.
189
+
190
+@<Header files to include@>=
191
+#include "webview.h"
192
+

Loading…
Cancel
Save