Typica is a free program for professional coffee roasters. https://typica.us
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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