PageRenderTime 55ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/webapp/op2-nox/webpage.cpp

https://github.com/kingst/op2-browser
C++ | 409 lines | 300 code | 45 blank | 64 comment | 70 complexity | 2ea60ccc50c9b93d29931577519cc366 MD5 | raw file
  1. /*========================================================
  2. **University of Illinois/NCSA
  3. **Open Source License
  4. **
  5. **Copyright (C) 2007-2008,The Board of Trustees of the University of
  6. **Illinois. All rights reserved.
  7. **
  8. **Developed by:
  9. **
  10. ** Research Group of Professor Sam King in the Department of Computer
  11. ** Science The University of Illinois at Urbana-Champaign
  12. ** http://www.cs.uiuc.edu/homes/kingst/Research.html
  13. **
  14. **Permission is hereby granted, free of charge, to any person obtaining a
  15. **copy of this software and associated documentation files (the
  16. **Ą°SoftwareĄą), to deal with the Software without restriction, including
  17. **without limitation the rights to use, copy, modify, merge, publish,
  18. **distribute, sublicense, and/or sell copies of the Software, and to
  19. **permit persons to whom the Software is furnished to do so, subject to
  20. **the following conditions:
  21. **
  22. *** Redistributions of source code must retain the above copyright notice,
  23. **this list of conditions and the following disclaimers.
  24. *** Redistributions in binary form must reproduce the above copyright
  25. **notice, this list of conditions and the following disclaimers in the
  26. **documentation and/or other materials provided with the distribution.
  27. *** Neither the names of <Name of Development Group, Name of Institution>,
  28. **nor the names of its contributors may be used to endorse or promote
  29. **products derived from this Software without specific prior written
  30. **permission.
  31. **
  32. **THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  33. **EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  34. **MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  35. **IN NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR
  36. **ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  37. **TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  38. **SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE.
  39. **==========================================================
  40. */
  41. #include "webpage.h"
  42. #include "webview.h"
  43. #include "OpNetwork.h"
  44. #include "jswindow.h"
  45. #include "OpDownloader.h"
  46. #include "FrameInit.h"
  47. #include "Message.h"
  48. #include <QMouseEvent>
  49. #include <QWheelEvent>
  50. #include <QKeyEvent>
  51. #include <QtUiTools/QtUiTools>
  52. #include <QBuffer>
  53. #include <QDataStream>
  54. #include <QNetworkReply>
  55. #include <qwebframe.h>
  56. #include <qwebelement.h>
  57. WebPage::WebPage(QObject *parent)
  58. : QWebPage(parent)
  59. , m_keyboardModifiers(Qt::NoModifier)
  60. , m_pressedButtons(Qt::NoButton)
  61. , m_openInNewTab(false)
  62. , m_posted(false)
  63. , m_back(false)
  64. , m_iframeHandled(IFRAME_HANDLED)
  65. {
  66. setNetworkAccessManager(OPNET::OpNetwork::instance()->networkAccessManager());
  67. connect(this, SIGNAL(unsupportedContent(QNetworkReply *)),
  68. this, SLOT(handleUnsupportedContent(QNetworkReply *)));
  69. connect(OPNET::OpNetwork::instance(), SIGNAL(userAction(int, const QByteArray&)),
  70. this, SLOT(replayEvent(int, const QByteArray&)));
  71. if (m_iframeHandled) {
  72. connect(this, SIGNAL(frameCreated(QWebFrame *)),
  73. this, SLOT(handleFrameCreated(QWebFrame *)));
  74. }
  75. }
  76. #ifdef OP_EXTENDED
  77. bool WebPage::acceptNavigationRequest(QWebFrame *frame, const QNetworkRequest &request, NavigationType type, const QByteArray& postData)
  78. {
  79. QString scheme = request.url().scheme();
  80. if (scheme == QLatin1String("mailto")
  81. || scheme == QLatin1String("ftp")) {
  82. // QDesktopServices::openUrl(request.url());
  83. return false;
  84. }
  85. if (IS_CRAWLER) // when crawler, we run the webapplication is the same process
  86. // make it easier for replay
  87. return QWebPage::acceptNavigationRequest(frame, request, type, postData);
  88. WebView::OpenType t = WebView::NewWebApp;
  89. WebView* view = qobject_cast<WebView*>(parent());
  90. Q_ASSERT(view != 0);
  91. // little trick to avoid double post
  92. if (m_posted) {
  93. m_posted = false;
  94. } else if (postData.size() > 0) {
  95. m_posted = true;
  96. }
  97. // ctrl open in new tab
  98. // ctrl-shift open in new tab and select
  99. // ctrl-alt open in new window
  100. if (type == QWebPage::NavigationTypeLinkClicked
  101. && (m_keyboardModifiers & Qt::ControlModifier
  102. || m_pressedButtons == Qt::MidButton)) {
  103. bool newWindow = (m_keyboardModifiers & Qt::AltModifier);
  104. if (newWindow) {
  105. t = WebView::NewWindow;
  106. } else {
  107. bool selectNewTab = (m_keyboardModifiers & Qt::ShiftModifier);
  108. if (selectNewTab)
  109. t = WebView::NewTabSelect;
  110. else
  111. t = WebView::NewTabNoSelect;
  112. }
  113. // check and load
  114. view->loadPolicy(request, postData, t);
  115. m_keyboardModifiers = Qt::NoModifier;
  116. m_pressedButtons = Qt::NoButton;
  117. return false;
  118. }
  119. //qDebug() << "navigation request url: " << request.url();
  120. QUrl::FormattingOptions format = QUrl::RemoveQuery | QUrl::RemoveFragment | QUrl::StripTrailingSlash;
  121. if (frame == mainFrame()) {
  122. //qDebug() << "mainFrame navigation request to " << request.url();
  123. m_loadingUrl = request.url();
  124. QUrl current = view->url();
  125. bool sop = (m_loadingUrl.scheme().toLower() == current.scheme().toLower())
  126. && (m_loadingUrl.host().toLower() == current.host().toLower())
  127. && (m_loadingUrl.port() == current.port());
  128. //QUrl::FormattingOptions format = QUrl::RemoveQuery | QUrl::RemoveFragment | QUrl::StripTrailingSlash;
  129. if (!sop //(view->loaded() || type == QWebPage::NavigationTypeLinkClicked) && !sop
  130. /*(m_loadingUrl.toString(format) != current.toString(format)) */) {
  131. t = WebView::NewWebApp;
  132. // check and load
  133. if (m_posted)
  134. view->loadPolicy(request, postData, t);
  135. else
  136. view->loadPolicy(request, QByteArray(), t);
  137. return false;
  138. } else {
  139. emit loadingUrl(m_loadingUrl);
  140. if ((type != NavigationTypeOther) && (type != NavigationTypeReload) && (type != NavigationTypeBackOrForward)
  141. || (view->m_userAction)) {
  142. QVariant var(m_loadingUrl.toString());
  143. OPNET::OpNetwork::instance()->sendUIMsg(MSG_addHistoryItem, getByteArray(var));
  144. view->m_userAction = false;
  145. }
  146. if (type == NavigationTypeBackOrForward) {
  147. //QVariant var(m_back);
  148. //OPNET::OpNetwork::instance()->sendUIMsg(MSG_navBackOrForward, getByteArray(var));
  149. m_back = false;
  150. }
  151. }
  152. }
  153. else if(frame == 0)
  154. {
  155. t = WebView::NewTabNoSelect;
  156. // check and load
  157. view->loadPolicy(request, postData, t);
  158. return false;
  159. }
  160. // same-origin and "about:blank" navigation requests fall-through to acceptNavigationRequest
  161. else if( m_iframeHandled &&
  162. (request.url().toString(format | QUrl::RemovePath) != view->url().toString(format | QUrl::RemovePath)
  163. && request.url().toString() != "about:blank")) {
  164. //qDebug() << "navigation request for sub-frame \"" << frame->frameName() << "\" to " << request.url() << " type: " << type;
  165. t = WebView::NewSubFrame;
  166. OPNET::OpNetwork::instance()->sendSysCall(MSG_EMBED_FRAME, 0, frame->frameName().toAscii());
  167. view->loadPolicy(request, postData, t);
  168. return false;
  169. }
  170. return QWebPage::acceptNavigationRequest(frame, request, type, postData);
  171. }
  172. #endif
  173. void WebPage::triggerAction(WebAction action, bool checked)
  174. {
  175. if (action == Back) {
  176. m_back = true;
  177. QVariant var(m_back);
  178. OPNET::OpNetwork::instance()->sendUIMsg(MSG_navBackOrForward, getByteArray(var));
  179. }
  180. if (action == Forward) {
  181. m_back = false;
  182. QVariant var(m_back);
  183. OPNET::OpNetwork::instance()->sendUIMsg(MSG_navBackOrForward, getByteArray(var));
  184. }
  185. QWebPage::triggerAction(action, checked);
  186. }
  187. QWebPage *WebPage::createWindow(QWebPage::WebWindowType type)
  188. {
  189. Q_UNUSED(type);
  190. if (IS_CRAWLER)
  191. return 0 ;
  192. // it reaches here if JavaScript tries to create a new window
  193. JSWindow* page = new JSWindow();
  194. WebView* view = qobject_cast<WebView*>(parent());
  195. page->setView(view);
  196. return page;
  197. }
  198. #if !defined(QT_NO_UITOOLS)
  199. QObject *WebPage::createPlugin(const QString &classId, const QUrl &url, const QStringList &paramNames, const QStringList &paramValues)
  200. {
  201. Q_UNUSED(url);
  202. Q_UNUSED(paramNames);
  203. Q_UNUSED(paramValues);
  204. QUiLoader loader;
  205. return loader.createWidget(classId, view());
  206. }
  207. #endif // !defined(QT_NO_UITOOLS)
  208. void WebPage::handleFrameCreated(QWebFrame *frame) {
  209. //qDebug() << "frame created = " << frame->frameName() << " " << frame->url();
  210. FrameInit *frameInit = new FrameInit(frame);
  211. connect(frame, SIGNAL(urlChanged(const QUrl &)),
  212. frameInit, SLOT(handleUrlChanged(const QUrl &)));
  213. connect(frame, SIGNAL(initialLayoutCompleted()),
  214. frameInit, SLOT(handleFrameLayoutComplete()));
  215. }
  216. void WebPage::handleUnsupportedContent(QNetworkReply *reply)
  217. {
  218. if (reply->error() == QNetworkReply::NoError) {
  219. if (reply->header(QNetworkRequest::ContentTypeHeader).isValid())
  220. qDebug() << "download it";
  221. new OpDownloader(reply);
  222. return;
  223. }
  224. if (reply->error() == QNetworkReply::ProtocolUnknownError) {
  225. // we currently don't support protocol other than http(s):// and file://
  226. // return;
  227. }
  228. //display notfound
  229. if (reply->url().isEmpty())
  230. return;
  231. QFile file(QLatin1String(":/notfound.html"));
  232. bool isOpened = file.open(QIODevice::ReadOnly);
  233. Q_ASSERT(isOpened);
  234. QString title = ("HTTP 404 Not Found");
  235. QString html = QString(QLatin1String(file.readAll()));
  236. QList<QWebFrame*> frames;
  237. frames.append(mainFrame());
  238. while (!frames.isEmpty()) {
  239. QWebFrame *frame = frames.takeFirst();
  240. if (frame->url() == reply->url()) {
  241. frame->setHtml(html, reply->url());
  242. return;
  243. }
  244. QList<QWebFrame *> children = frame->childFrames();
  245. foreach (QWebFrame *frame, children)
  246. frames.append(frame);
  247. }
  248. if (m_loadingUrl == reply->url()) {
  249. mainFrame()->setHtml(html, reply->url());
  250. }
  251. }
  252. bool WebPage::event(QEvent *ev)
  253. {
  254. QMouseEvent* mouseEvent = NULL;
  255. QWheelEvent* wheelEvent = NULL;
  256. QKeyEvent* keyEvent = NULL;
  257. QByteArray byteArray;
  258. QBuffer buffer(&byteArray);
  259. buffer.open(QIODevice::ReadWrite);
  260. QDataStream out(&buffer);
  261. out << (int) ev->type();
  262. switch (ev->type()) {
  263. case QEvent::MouseMove:
  264. case QEvent::MouseButtonPress:
  265. case QEvent::MouseButtonDblClick:
  266. case QEvent::MouseButtonRelease:
  267. if (OPNET::OpNetwork::instance()->isReplay() || OPNET::OpNetwork::instance()->isReplica())
  268. return false;
  269. mouseEvent = (static_cast<QMouseEvent*>(ev));
  270. out << mouseEvent->pos() << mouseEvent->globalPos()
  271. << (int) mouseEvent->button() << (int) mouseEvent->buttons()
  272. << (int) mouseEvent->modifiers();
  273. OPNET::OpNetwork::instance()->sendSysCall(MSG_LOG_USER_INPUT, (int) ev->type(), byteArray);
  274. break;
  275. case QEvent::Wheel:
  276. if (OPNET::OpNetwork::instance()->isReplay() || OPNET::OpNetwork::instance()->isReplica())
  277. return false;;
  278. wheelEvent = (static_cast<QWheelEvent*>(ev));
  279. out << wheelEvent->pos() << wheelEvent->globalPos()
  280. << wheelEvent->delta() << (int) wheelEvent->buttons()
  281. << (int) wheelEvent->modifiers() << (int) wheelEvent->orientation();
  282. OPNET::OpNetwork::instance()->sendSysCall(MSG_LOG_USER_INPUT, (int) ev->type(), byteArray);
  283. break;
  284. case QEvent::KeyPress:
  285. case QEvent::KeyRelease:
  286. if (OPNET::OpNetwork::instance()->isReplay() || OPNET::OpNetwork::instance()->isReplica())
  287. return false;
  288. keyEvent = (static_cast<QKeyEvent*>(ev));
  289. out << keyEvent->key() << (int) keyEvent->modifiers()
  290. << keyEvent->text() << keyEvent->isAutoRepeat()
  291. << (int) keyEvent->count();
  292. OPNET::OpNetwork::instance()->sendSysCall(MSG_LOG_USER_INPUT, (int) ev->type(), byteArray);
  293. break;
  294. default:
  295. break;
  296. }
  297. return QWebPage::event(ev);
  298. }
  299. bool WebPage::replayEvent(int type, const QByteArray& args)
  300. {
  301. QDataStream stream(args);
  302. int _type;
  303. stream >> _type;
  304. Q_ASSERT(type == _type);
  305. switch (type) {
  306. case QEvent::MouseMove:
  307. case QEvent::MouseButtonPress:
  308. case QEvent::MouseButtonDblClick:
  309. case QEvent::MouseButtonRelease:
  310. {
  311. QPoint pos;
  312. QPoint globalPos;
  313. int button;
  314. int buttons;
  315. int modifiers;
  316. stream >> pos >> globalPos >> button >> buttons >> modifiers;
  317. QMouseEvent mouseEvent((QEvent::Type) type, pos, globalPos,
  318. (Qt::MouseButton) button,
  319. (Qt::MouseButtons) buttons,
  320. (Qt::KeyboardModifiers) modifiers);
  321. QWebPage::event(&mouseEvent);
  322. break;
  323. }
  324. case QEvent::Wheel:
  325. {
  326. QPoint pos;
  327. QPoint globalPos;
  328. int delta;
  329. // Qt::MouseButtons
  330. int buttons;
  331. // Qt::KeyboardModifiers
  332. int modifiers;
  333. // Qt::Orientation
  334. int orient;
  335. stream >> pos >> globalPos >> delta >> buttons
  336. >> modifiers >> orient;
  337. QWheelEvent wheelEvent(pos, globalPos, delta,
  338. (Qt::MouseButtons)buttons,
  339. (Qt::KeyboardModifiers)modifiers,
  340. (Qt::Orientation)orient);
  341. QWebPage::event(&wheelEvent);
  342. break;
  343. }
  344. case QEvent::KeyPress:
  345. case QEvent::KeyRelease:
  346. {
  347. int key;
  348. int modifiers;
  349. QString text;
  350. bool autorep;
  351. int count;
  352. stream >> key >> modifiers >> text >> autorep >> count;
  353. QKeyEvent keyEvent((QEvent::Type)type, key,
  354. (Qt::KeyboardModifiers) modifiers,
  355. text, autorep, count);
  356. QWebPage::event(&keyEvent);
  357. break;
  358. }
  359. default:
  360. std::cerr << "Unhandled user event type" << std::endl;
  361. return false;
  362. }
  363. return true;
  364. }