fb2text.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844
  1. #include "fb2text.hpp"
  2. #include "fb2dlgs.hpp"
  3. #include "fb2read.hpp"
  4. #include "fb2save.hpp"
  5. #include "fb2utils.h"
  6. #include "fb2html.h"
  7. #include "fb2xml2.h"
  8. #include <QAction>
  9. #include <QBoxLayout>
  10. #include <QDockWidget>
  11. #include <QFileDialog>
  12. #include <QInputDialog>
  13. #include <QMainWindow>
  14. #include <QMenu>
  15. #include <QNetworkRequest>
  16. #include <QStyle>
  17. #include <QStyleOptionFrame>
  18. #include <QToolBar>
  19. #include <QToolTip>
  20. #include <QUndoCommand>
  21. #include <QUndoStack>
  22. #include <QWebElement>
  23. #include <QWebInspector>
  24. #include <QWebFrame>
  25. #include <QWebPage>
  26. #include <QtDebug>
  27. //---------------------------------------------------------------------------
  28. // FbTextLogger
  29. //---------------------------------------------------------------------------
  30. void FbTextLogger::trace(const QString &text)
  31. {
  32. qCritical() << text;
  33. }
  34. //---------------------------------------------------------------------------
  35. // FbNoteView
  36. //---------------------------------------------------------------------------
  37. class FbNoteView : public QWebView
  38. {
  39. public:
  40. explicit FbNoteView(QWidget *parent, const QUrl &url);
  41. void hint(const QWebElement element, const QRect &rect);
  42. protected:
  43. void paintEvent(QPaintEvent *event);
  44. const QUrl m_url;
  45. };
  46. FbNoteView::FbNoteView(QWidget *parent, const QUrl &url)
  47. : QWebView(parent)
  48. , m_url(url)
  49. {
  50. }
  51. void FbNoteView::paintEvent(QPaintEvent *event)
  52. {
  53. QWebView::paintEvent(event);
  54. QPainter painter(this);
  55. painter.setPen(Qt::black);
  56. QSize size = geometry().size() - QSize(1, 1);
  57. painter.drawRect( QRect(QPoint(0, 0), size) );
  58. }
  59. void FbNoteView::hint(const QWebElement element, const QRect &rect)
  60. {
  61. QString html = element.toOuterXml();
  62. html.prepend(
  63. "<body bgcolor=lightyellow style='overflow:hidden;padding:0;margin:0;margin-top:2;'>"
  64. "<fb:body name=notes style='padding:0;margin:0;'>"
  65. );
  66. html.append("</fb:body></body>");
  67. setGeometry(rect);
  68. setHtml(html, m_url);
  69. show();
  70. }
  71. //---------------------------------------------------------------------------
  72. // FbTextPage
  73. //---------------------------------------------------------------------------
  74. FbTextPage::FbTextPage(QObject *parent)
  75. : QWebPage(parent)
  76. , m_logger(this)
  77. {
  78. QWebSettings *s = settings();
  79. s->setAttribute(QWebSettings::AutoLoadImages, true);
  80. s->setAttribute(QWebSettings::DeveloperExtrasEnabled, true);
  81. s->setAttribute(QWebSettings::JavaEnabled, false);
  82. s->setAttribute(QWebSettings::JavascriptEnabled, true);
  83. s->setAttribute(QWebSettings::PrivateBrowsingEnabled, true);
  84. s->setAttribute(QWebSettings::PluginsEnabled, false);
  85. s->setAttribute(QWebSettings::ZoomTextOnly, true);
  86. s->setUserStyleSheetUrl(QUrl::fromLocalFile(":style.css"));
  87. setContentEditable(true);
  88. setNetworkAccessManager(new FbNetworkAccessManager(this));
  89. connect(this, SIGNAL(loadFinished(bool)), SLOT(loadFinished()));
  90. connect(this, SIGNAL(contentsChanged()), SLOT(fixContents()));
  91. }
  92. FbNetworkAccessManager *FbTextPage::temp()
  93. {
  94. return qobject_cast<FbNetworkAccessManager*>(networkAccessManager());
  95. }
  96. bool FbTextPage::acceptNavigationRequest(QWebFrame *frame, const QNetworkRequest &request, NavigationType type)
  97. {
  98. Q_UNUSED(frame);
  99. if (type == NavigationTypeLinkClicked) {
  100. qCritical() << request.url().fragment();
  101. return false;
  102. // QToolTip::showText(request.url().fragment());
  103. }
  104. return QWebPage::acceptNavigationRequest(frame, request, type);
  105. }
  106. QString FbTextPage::div(const QString &style, const QString &text)
  107. {
  108. return QString("<div class=%1>%2</div>").arg(style).arg(text);
  109. }
  110. QString FbTextPage::p(const QString &text)
  111. {
  112. return QString("<p>%1</p>").arg(text);
  113. }
  114. FbTextElement FbTextPage::body()
  115. {
  116. return doc().findFirst("body");
  117. }
  118. FbTextElement FbTextPage::doc()
  119. {
  120. return mainFrame()->documentElement();
  121. }
  122. void FbTextPage::push(QUndoCommand * command, const QString &text)
  123. {
  124. undoStack()->beginMacro(text);
  125. undoStack()->push(command);
  126. undoStack()->endMacro();
  127. }
  128. void FbTextPage::update()
  129. {
  130. emit contentsChanged();
  131. emit selectionChanged();
  132. }
  133. void FbTextPage::appendSection(const FbTextElement &parent)
  134. {
  135. QString html = div("section", div("title", p()) + p());
  136. FbTextElement element = parent;
  137. element.appendInside(html);
  138. element = parent.lastChild();
  139. QUndoCommand * command = new FbInsertCmd(element);
  140. push(command, tr("Append section"));
  141. }
  142. void FbTextPage::insertBody()
  143. {
  144. QString html = div("body", div("title", p()) + div("section", div("title", p()) + p()));
  145. FbTextElement element = body();
  146. element.appendInside(html);
  147. element = element.lastChild();
  148. QUndoCommand * command = new FbInsertCmd(element);
  149. push(command, tr("Append body"));
  150. }
  151. void FbTextPage::insertSection()
  152. {
  153. FbTextElement element = current();
  154. while (!element.isNull()) {
  155. if (element.isSection() || element.isBody()) {
  156. appendSection(element);
  157. break;
  158. }
  159. element = element.parent();
  160. }
  161. }
  162. void FbTextPage::insertTitle()
  163. {
  164. FbTextElement element = current();
  165. while (!element.isNull()) {
  166. FbTextElement parent = element.parent();
  167. if ((parent.isSection() || parent.isBody()) && !parent.hasTitle()) {
  168. QString html = div("title", p());
  169. parent.prependInside(html);
  170. element = parent.firstChild();
  171. QUndoCommand * command = new FbInsertCmd(element);
  172. push(command, tr("Insert title"));
  173. break;
  174. }
  175. element = parent;
  176. }
  177. }
  178. void FbTextPage::insertSubtitle()
  179. {
  180. FbTextElement element = current();
  181. while (!element.isNull()) {
  182. FbTextElement parent = element.parent();
  183. if (parent.isSection()) {
  184. QString html = div("subtitle", p());
  185. if (element.isTitle()) {
  186. element.appendOutside(html);
  187. element = element.nextSibling();
  188. } else {
  189. element.prependOutside(html);
  190. element = element.previousSibling();
  191. }
  192. QUndoCommand * command = new FbInsertCmd(element);
  193. push(command, tr("Insert subtitle"));
  194. break;
  195. }
  196. element = parent;
  197. }
  198. }
  199. void FbTextPage::insertPoem()
  200. {
  201. FbTextElement element = current();
  202. while (!element.isNull()) {
  203. FbTextElement parent = element.parent();
  204. if (parent.isSection()) {
  205. QString html = div("poem", div("stanza", p()));
  206. if (element.isTitle()) {
  207. element.appendOutside(html);
  208. element = element.nextSibling();
  209. } else {
  210. element.prependOutside(html);
  211. element = element.previousSibling();
  212. }
  213. QUndoCommand * command = new FbInsertCmd(element);
  214. push(command, tr("Insert poem"));
  215. break;
  216. }
  217. element = parent;
  218. }
  219. }
  220. void FbTextPage::insertStanza()
  221. {
  222. FbTextElement element = current();
  223. while (!element.isNull()) {
  224. if (element.isStanza()) {
  225. QString html = div("stanza", p());
  226. element.appendOutside(html);
  227. element = element.nextSibling();
  228. QUndoCommand * command = new FbInsertCmd(element);
  229. push(command, tr("Append stanza"));
  230. break;
  231. }
  232. element = element.parent();
  233. }
  234. }
  235. void FbTextPage::insertAnnot()
  236. {
  237. }
  238. void FbTextPage::insertAuthor()
  239. {
  240. }
  241. void FbTextPage::insertEpigraph()
  242. {
  243. const QString type = "epigraph";
  244. FbTextElement element = current();
  245. while (!element.isNull()) {
  246. if (element.hasSubtype(type)) {
  247. QString html = div("epigraph", p());
  248. element = element.insertInside(type, html);
  249. QUndoCommand * command = new FbInsertCmd(element);
  250. push(command, tr("Insert epigraph"));
  251. break;
  252. }
  253. element = element.parent();
  254. }
  255. }
  256. void FbTextPage::insertDate()
  257. {
  258. }
  259. void FbTextPage::insertText()
  260. {
  261. FbTextElement element = current();
  262. while (!element.isNull()) {
  263. if (element.tagName() == "DIV") {
  264. if (element.parent().isBody()) break;
  265. element.appendOutside("<p><br></p>");
  266. element.nextSibling().select();
  267. return;
  268. }
  269. element = element.parent();
  270. }
  271. }
  272. void FbTextPage::createDiv(const QString &className)
  273. {
  274. QString style = className;
  275. QString js1 = jScript("section_get.js");
  276. QString result = mainFrame()->evaluateJavaScript(js1).toString();
  277. QStringList list = result.split("|");
  278. if (list.count() < 2) return;
  279. const QString location = list[0];
  280. const QString position = list[1];
  281. if (style == "title" && position.left(2) != "0,") style.prepend("sub");
  282. FbTextElement original = element(location);
  283. FbTextElement duplicate = original.clone();
  284. original.appendOutside(duplicate);
  285. original.takeFromDocument();
  286. QString js2 = jScript("section_new.js") + ";f(this,'%1',%2)";
  287. duplicate.evaluateJavaScript(js2.arg(style).arg(position));
  288. QUndoCommand * command = new FbReplaceCmd(original, duplicate);
  289. push(command, tr("Create <%1>").arg(className));
  290. }
  291. void FbTextPage::createSection()
  292. {
  293. createDiv("section");
  294. }
  295. void FbTextPage::deleteSection()
  296. {
  297. FbTextElement element = current();
  298. while (!element.isNull()) {
  299. if (element.isSection()) {
  300. if (element.parent().isBody()) return;
  301. FbTextElement original = element.parent();
  302. FbTextElement duplicate = original.clone();
  303. int index = element.index();
  304. original.appendOutside(duplicate);
  305. original.takeFromDocument();
  306. element = duplicate.child(index);
  307. if (index) {
  308. FbTextElement title = element.firstChild();
  309. if (title.isTitle()) {
  310. title.removeClass("title");
  311. title.addClass("subtitle");
  312. }
  313. }
  314. QString xml = element.toInnerXml();
  315. element.setOuterXml(xml);
  316. QUndoCommand * command = new FbReplaceCmd(original, duplicate);
  317. push(command, tr("Remove section"));
  318. element.select();
  319. break;
  320. }
  321. element = element.parent();
  322. }
  323. }
  324. void FbTextPage::createTitle()
  325. {
  326. createDiv("title");
  327. }
  328. FbTextElement FbTextPage::current()
  329. {
  330. return element(location());
  331. }
  332. FbTextElement FbTextPage::element(const QString &location)
  333. {
  334. if (location.isEmpty()) return FbTextElement();
  335. QStringList list = location.split(",", QString::SkipEmptyParts);
  336. QStringListIterator iterator(list);
  337. QWebElement result = doc();
  338. while (iterator.hasNext()) {
  339. QString str = iterator.next();
  340. int pos = str.indexOf("=");
  341. QString tag = str.left(pos);
  342. int key = str.mid(pos + 1).toInt();
  343. if (key < 0) break;
  344. result = result.firstChild();
  345. while (0 < key--) result = result.nextSibling();
  346. }
  347. return result;
  348. }
  349. QString FbTextPage::location()
  350. {
  351. QString javascript = "location(document.getSelection().anchorNode)";
  352. return mainFrame()->evaluateJavaScript(javascript).toString();
  353. }
  354. QString FbTextPage::status()
  355. {
  356. QString javascript = jScript("get_status.js");
  357. return mainFrame()->evaluateJavaScript(javascript).toString();
  358. }
  359. void FbTextPage::loadFinished()
  360. {
  361. mainFrame()->evaluateJavaScript("window.focus()");
  362. mainFrame()->addToJavaScriptWindowObject("logger", &m_logger);
  363. FbTextElement element = body().findFirst("div.body");
  364. if (element.isNull()) element = body();
  365. element.select();
  366. }
  367. void FbTextPage::fixContents()
  368. {
  369. foreach (QWebElement span, doc().findAll("span.apple-style-span[style]")) {
  370. span.removeAttribute("style");
  371. }
  372. foreach (QWebElement span, doc().findAll("[style]")) {
  373. span.removeAttribute("style");
  374. }
  375. }
  376. //---------------------------------------------------------------------------
  377. // FbTextBase
  378. //---------------------------------------------------------------------------
  379. void FbTextBase::addTools(QToolBar *tool)
  380. {
  381. QAction *act;
  382. act = pageAction(QWebPage::Undo);
  383. act->setIcon(FbIcon("edit-undo"));
  384. act->setText(QObject::tr("&Undo"));
  385. act->setPriority(QAction::LowPriority);
  386. act->setShortcut(QKeySequence::Undo);
  387. tool->addAction(act);
  388. act = pageAction(QWebPage::Redo);
  389. act->setIcon(FbIcon("edit-redo"));
  390. act->setText(QObject::tr("&Redo"));
  391. act->setPriority(QAction::LowPriority);
  392. act->setShortcut(QKeySequence::Redo);
  393. tool->addAction(act);
  394. tool->addSeparator();
  395. act = pageAction(QWebPage::Cut);
  396. act->setIcon(FbIcon("edit-cut"));
  397. act->setText(QObject::tr("Cu&t"));
  398. act->setPriority(QAction::LowPriority);
  399. act->setShortcuts(QKeySequence::Cut);
  400. act->setStatusTip(QObject::tr("Cut the current selection's contents to the clipboard"));
  401. tool->addAction(act);
  402. act = pageAction(QWebPage::Copy);
  403. act->setIcon(FbIcon("edit-copy"));
  404. act->setText(QObject::tr("&Copy"));
  405. act->setPriority(QAction::LowPriority);
  406. act->setShortcuts(QKeySequence::Copy);
  407. act->setStatusTip(QObject::tr("Copy the current selection's contents to the clipboard"));
  408. tool->addAction(act);
  409. act = pageAction(QWebPage::Paste);
  410. act->setIcon(FbIcon("edit-paste"));
  411. act->setText(QObject::tr("&Paste"));
  412. act->setPriority(QAction::LowPriority);
  413. act->setShortcuts(QKeySequence::Paste);
  414. act->setStatusTip(QObject::tr("Paste the clipboard's contents into the current selection"));
  415. tool->addAction(act);
  416. tool->addSeparator();
  417. act = pageAction(QWebPage::RemoveFormat);
  418. act->setText(QObject::tr("Clear format"));
  419. act->setIcon(FbIcon("edit-clear"));
  420. act = pageAction(QWebPage::ToggleBold);
  421. act->setIcon(FbIcon("format-text-bold"));
  422. act->setText(QObject::tr("&Bold"));
  423. tool->addAction(act);
  424. act = pageAction(QWebPage::ToggleItalic);
  425. act->setIcon(FbIcon("format-text-italic"));
  426. act->setText(QObject::tr("&Italic"));
  427. tool->addAction(act);
  428. act = pageAction(QWebPage::ToggleStrikethrough);
  429. act->setIcon(FbIcon("format-text-strikethrough"));
  430. act->setText(QObject::tr("&Strikethrough"));
  431. tool->addAction(act);
  432. act = pageAction(QWebPage::ToggleSuperscript);
  433. act->setIcon(FbIcon("format-text-superscript"));
  434. act->setText(QObject::tr("Su&perscript"));
  435. tool->addAction(act);
  436. act = pageAction(QWebPage::ToggleSubscript);
  437. act->setIcon(FbIcon("format-text-subscript"));
  438. act->setText(QObject::tr("Su&bscript"));
  439. tool->addAction(act);
  440. }
  441. //---------------------------------------------------------------------------
  442. // FbTextEdit
  443. //---------------------------------------------------------------------------
  444. FbTextEdit::FbTextEdit(QWidget *parent)
  445. : FbTextBase(parent)
  446. , m_noteView(0)
  447. , m_thread(0)
  448. {
  449. setContextMenuPolicy(Qt::CustomContextMenu);
  450. connect(this, SIGNAL(customContextMenuRequested(QPoint)), SLOT(contextMenu(QPoint)));
  451. setPage(new FbTextPage(this));
  452. }
  453. FbTextEdit::~FbTextEdit()
  454. {
  455. if (m_noteView) delete m_noteView;
  456. }
  457. FbTextPage *FbTextEdit::page()
  458. {
  459. return qobject_cast<FbTextPage*>(FbTextBase::page());
  460. }
  461. FbNetworkAccessManager *FbTextEdit::files()
  462. {
  463. return page()->temp();
  464. }
  465. FbNoteView & FbTextEdit::noteView()
  466. {
  467. if (m_noteView) return *m_noteView;
  468. m_noteView = new FbNoteView(qobject_cast<QWidget*>(parent()), url());
  469. m_noteView->setPage(new FbTextPage(this));
  470. m_noteView->page()->setNetworkAccessManager(page()->networkAccessManager());
  471. m_noteView->page()->setContentEditable(false);
  472. m_noteView->setGeometry(QRect(100, 100, 400, 200));
  473. return *m_noteView;
  474. }
  475. QWebElement FbTextEdit::body()
  476. {
  477. return doc().findFirst("body");
  478. }
  479. QWebElement FbTextEdit::doc()
  480. {
  481. return page()->mainFrame()->documentElement();
  482. }
  483. void FbTextEdit::mouseMoveEvent(QMouseEvent *event)
  484. {
  485. m_point = event->pos();
  486. QWebView::mouseMoveEvent(event);
  487. }
  488. void FbTextEdit::contextMenu(const QPoint &pos)
  489. {
  490. QMenu menu, *submenu;
  491. submenu = menu.addMenu(tr("Fo&rmat"));
  492. submenu->addAction(pageAction(QWebPage::RemoveFormat));
  493. submenu->addSeparator();
  494. submenu->addAction(pageAction(QWebPage::ToggleBold));
  495. submenu->addAction(pageAction(QWebPage::ToggleItalic));
  496. submenu->addAction(pageAction(QWebPage::ToggleStrikethrough));
  497. submenu->addAction(pageAction(QWebPage::ToggleSuperscript));
  498. submenu->addAction(pageAction(QWebPage::ToggleSubscript));
  499. menu.addSeparator();
  500. menu.addAction(pageAction(QWebPage::Cut));
  501. menu.addAction(pageAction(QWebPage::Copy));
  502. menu.addAction(pageAction(QWebPage::Paste));
  503. menu.addAction(pageAction(QWebPage::PasteAndMatchStyle));
  504. menu.exec(mapToGlobal(pos));
  505. }
  506. void FbTextEdit::linkHovered(const QString &link, const QString &title, const QString &textContent)
  507. {
  508. Q_UNUSED(title);
  509. Q_UNUSED(textContent);
  510. const QString href = QUrl(link).fragment();
  511. if (href.isEmpty()) {
  512. if (m_noteView) m_noteView->hide();
  513. return;
  514. }
  515. const QString query = QString("fb\\:section#%1").arg(href);
  516. const QWebElement element = doc().findFirst(query);
  517. if (element.isNull()) {
  518. if (m_noteView) m_noteView->hide();
  519. return;
  520. }
  521. QRect rect = geometry();
  522. QSize size = element.geometry().size() + QSize(2, 4);
  523. int center = rect.size().height() / 2;
  524. int h = size.height();
  525. if (h > center) size.setHeight(center - 10);
  526. int x = (rect.size().width() - size.width()) / 2;
  527. int y = m_point.y();
  528. if ( y > h ) y = y - h - 10; else y = y + 10;
  529. QPoint point = QPoint(x, y) + rect.topLeft();
  530. noteView().hint(element, QRect(point, size));
  531. }
  532. void FbTextEdit::load(const QString &filename, const QString &xml)
  533. {
  534. if (m_thread) return;
  535. m_thread = new FbReadThread(this, filename, xml);
  536. FbTextPage *page = new FbTextPage(m_thread);
  537. m_thread->setPage(page);
  538. m_thread->setTemp(page->temp());
  539. m_thread->start();
  540. }
  541. void FbTextEdit::html(QString html)
  542. {
  543. if (!m_thread) return;
  544. static int number = 0;
  545. QWebSettings::clearMemoryCaches();
  546. QUrl url(QString("fb2:/%1/").arg(number++));
  547. FbTextPage *page = m_thread->page();
  548. setPage(page);
  549. page->setParent(this);
  550. page->temp()->setPath(url.path());
  551. setHtml(html, url);
  552. connect(page, SIGNAL(linkHovered(QString,QString,QString)), SLOT(linkHovered(QString,QString,QString)));
  553. m_thread->deleteLater();
  554. m_thread = 0;
  555. }
  556. bool FbTextEdit::save(QIODevice *device, const QString &codec)
  557. {
  558. FbSaveWriter writer(*this, device);
  559. if (!codec.isEmpty()) writer.setCodec(codec.toLatin1());
  560. bool ok = FbSaveHandler(writer).save();
  561. if (ok) page()->undoStack()->setClean();
  562. return ok;
  563. }
  564. bool FbTextEdit::save(QByteArray *array)
  565. {
  566. FbSaveWriter writer(*this, array);
  567. return FbSaveHandler(writer).save();
  568. }
  569. bool FbTextEdit::save(QString *string)
  570. {
  571. // Use class QByteArray instead QString
  572. // to store information about encoding.
  573. QByteArray data;
  574. bool ok = save(&data);
  575. if (ok) *string = QString::fromUtf8(data.data());
  576. return ok;
  577. }
  578. void FbTextEdit::data(QString name, QByteArray data)
  579. {
  580. files()->data(name, data);
  581. }
  582. void FbTextEdit::zoomIn()
  583. {
  584. qreal zoom = zoomFactor();
  585. setZoomFactor(zoom * 1.1);
  586. }
  587. void FbTextEdit::zoomOut()
  588. {
  589. qreal zoom = zoomFactor();
  590. setZoomFactor(zoom * 0.9);
  591. }
  592. void FbTextEdit::zoomReset()
  593. {
  594. setZoomFactor(1);
  595. }
  596. bool FbTextEdit::actionEnabled(QWebPage::WebAction action)
  597. {
  598. QAction *act = pageAction(action);
  599. return act ? act->isEnabled() : false;
  600. }
  601. bool FbTextEdit::actionChecked(QWebPage::WebAction action)
  602. {
  603. QAction *act = pageAction(action);
  604. return act ? act->isChecked() : false;
  605. }
  606. bool FbTextEdit::BoldChecked()
  607. {
  608. return pageAction(QWebPage::ToggleBold)->isChecked();
  609. }
  610. bool FbTextEdit::ItalicChecked()
  611. {
  612. return pageAction(QWebPage::ToggleItalic)->isChecked();
  613. }
  614. bool FbTextEdit::StrikeChecked()
  615. {
  616. return pageAction(QWebPage::ToggleStrikethrough)->isChecked();
  617. }
  618. bool FbTextEdit::SubChecked()
  619. {
  620. return pageAction(QWebPage::ToggleSubscript)->isChecked();
  621. }
  622. bool FbTextEdit::SupChecked()
  623. {
  624. return pageAction(QWebPage::ToggleSuperscript)->isChecked();
  625. }
  626. void FbTextEdit::find()
  627. {
  628. FbTextFindDlg dlg(*this);
  629. dlg.exec();
  630. }
  631. void FbTextEdit::insertImage()
  632. {
  633. QString filters;
  634. filters += tr("Common Graphics (*.png *.jpg *.jpeg *.gif);;");
  635. filters += tr("Portable Network Graphics (PNG) (*.png);;");
  636. filters += tr("JPEG (*.jpg *.jpeg);;");
  637. filters += tr("Graphics Interchange Format (*.gif);;");
  638. filters += tr("All Files (*)");
  639. QString path = QFileDialog::getOpenFileName(this, tr("Insert image..."), QString(), filters);
  640. if (path.isEmpty()) return;
  641. QFile file(path);
  642. if (!file.open(QIODevice::ReadOnly)) return;
  643. QByteArray data = file.readAll();
  644. QString name = files()->add(path, data);
  645. execCommand("insertImage", name.prepend("#"));
  646. }
  647. void FbTextEdit::insertNote()
  648. {
  649. FbNoteDlg dlg(*this);
  650. dlg.exec();
  651. }
  652. void FbTextEdit::insertLink()
  653. {
  654. bool ok;
  655. QString text = QInputDialog::getText(this, tr("Insert hyperlink"), tr("URL:"), QLineEdit::Normal, QString(), &ok);
  656. if (ok && !text.isEmpty()) execCommand("CreateLink", text);
  657. }
  658. void FbTextEdit::execCommand(const QString &cmd, const QString &arg)
  659. {
  660. QString javascript = QString("document.execCommand(\"%1\",false,\"%2\")").arg(cmd).arg(arg);
  661. page()->mainFrame()->evaluateJavaScript(javascript);
  662. }
  663. //---------------------------------------------------------------------------
  664. // FbTextFrame
  665. //---------------------------------------------------------------------------
  666. FbTextFrame::FbTextFrame(QWidget *parent, QAction *action)
  667. : QFrame(parent)
  668. , m_view(this)
  669. , m_dock(0)
  670. {
  671. setFrameShape(QFrame::StyledPanel);
  672. setFrameShadow(QFrame::Sunken);
  673. QLayout * layout = new QBoxLayout(QBoxLayout::LeftToRight, this);
  674. layout->setSpacing(0);
  675. layout->setMargin(0);
  676. layout->addWidget(&m_view);
  677. connect(action, SIGNAL(triggered()), SLOT(showInspector()));
  678. }
  679. FbTextFrame::~FbTextFrame()
  680. {
  681. if (m_dock) m_dock->deleteLater();
  682. }
  683. void FbTextFrame::showInspector()
  684. {
  685. if (m_dock) {
  686. m_dock->setVisible(m_dock->isHidden());
  687. return;
  688. }
  689. QMainWindow *main = qobject_cast<QMainWindow*>(parent());
  690. if (!main) return;
  691. m_dock = new QDockWidget(tr("Web inspector"), this);
  692. m_dock->setFeatures(QDockWidget::AllDockWidgetFeatures);
  693. main->addDockWidget(Qt::BottomDockWidgetArea, m_dock);
  694. QWebInspector *inspector = new QWebInspector(this);
  695. inspector->setPage(m_view.page());
  696. m_dock->setWidget(inspector);
  697. connect(m_dock, SIGNAL(visibilityChanged(bool)), main, SIGNAL(showInspectorChecked(bool)));
  698. connect(m_dock, SIGNAL(destroyed()), SLOT(dockDestroyed()));
  699. }
  700. void FbTextFrame::hideInspector()
  701. {
  702. if (m_dock) m_dock->hide();
  703. }
  704. void FbTextFrame::dockDestroyed()
  705. {
  706. m_dock = 0;
  707. }
  708. //---------------------------------------------------------------------------
  709. // FbTextAction
  710. //---------------------------------------------------------------------------
  711. FbTextAction::FbTextAction(const QString &text, QWebPage::WebAction action, QObject* parent)
  712. : QAction(text, parent)
  713. , m_action(action)
  714. {
  715. }
  716. FbTextAction::FbTextAction(const QIcon &icon, const QString &text, QWebPage::WebAction action, QObject* parent)
  717. : QAction(icon, text, parent)
  718. , m_action(action)
  719. {
  720. }
  721. void FbTextAction::updateChecked()
  722. {
  723. if (QAction * act = action(m_action)) setChecked(act->isChecked());
  724. }
  725. void FbTextAction::updateEnabled()
  726. {
  727. if (QAction * act = action(m_action)) setEnabled(act->isEnabled());
  728. }