fb2main.cpp 33 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034
  1. #include <QtGui>
  2. #include <QtDebug>
  3. #include <QTreeView>
  4. #include <QWebFrame>
  5. #include "fb2main.hpp"
  6. #include "fb2code.hpp"
  7. #include "fb2dlgs.hpp"
  8. #include "fb2read.hpp"
  9. #include "fb2save.hpp"
  10. #include "fb2text.hpp"
  11. #include "fb2tree.hpp"
  12. #include "fb2head.hpp"
  13. #include "fb2utils.h"
  14. //---------------------------------------------------------------------------
  15. // FbDockWidget
  16. //---------------------------------------------------------------------------
  17. FbDockWidget::FbDockWidget(const QString &title, QWidget *parent, Qt::WindowFlags flags)
  18. : QDockWidget(title, parent, flags)
  19. {
  20. setFeatures(QDockWidget::AllDockWidgetFeatures);
  21. setAttribute(Qt::WA_DeleteOnClose);
  22. }
  23. //---------------------------------------------------------------------------
  24. // FbTextAction
  25. //---------------------------------------------------------------------------
  26. QAction * FbTextAction::action(QWebPage::WebAction action)
  27. {
  28. FbMainWindow * main = qobject_cast<FbMainWindow*>(parent());
  29. if (!main) return 0;
  30. FbTextPage * page = main->page();
  31. if (!page) return 0;
  32. return page->action(action);
  33. }
  34. //---------------------------------------------------------------------------
  35. // FbMainWindow
  36. //---------------------------------------------------------------------------
  37. FbMainWindow::FbMainWindow(const QString &filename, ViewMode mode)
  38. : QMainWindow()
  39. , textFrame(0)
  40. , codeEdit(0)
  41. , headTree(0)
  42. , noteEdit(0)
  43. , toolEdit(0)
  44. , dockTree(0)
  45. , dockImgs(0)
  46. , inspector(0)
  47. , messageEdit(0)
  48. , isSwitched(false)
  49. , isUntitled(true)
  50. {
  51. connect(qApp, SIGNAL(logMessage(QString)), SLOT(logMessage(QString)));
  52. setUnifiedTitleAndToolBarOnMac(true);
  53. setAttribute(Qt::WA_DeleteOnClose);
  54. setWindowIcon(QIcon(":icon.ico"));
  55. createActions();
  56. createStatusBar();
  57. readSettings();
  58. setCurrentFile(filename);
  59. if (mode == FB2) {
  60. QString filepath = filename.isEmpty() ? ":blank.fb2" : filename;
  61. FbTextPage *page = new FbTextPage(this);
  62. if (page->load(filepath, QString())) {
  63. viewText(page);
  64. } else {
  65. delete page;
  66. viewCode();
  67. if (!filename.isEmpty()) loadXML(filepath);
  68. }
  69. } else {
  70. viewCode();
  71. if (!filename.isEmpty()) loadXML(filename);
  72. }
  73. }
  74. FbTextPage * FbMainWindow::page()
  75. {
  76. return textFrame ? textFrame->view()->page() : 0;
  77. }
  78. void FbMainWindow::logMessage(const QString &message)
  79. {
  80. if (!messageEdit) {
  81. messageEdit = new QTextEdit(this);
  82. connect(messageEdit, SIGNAL(destroyed()), SLOT(logDestroyed()));
  83. QDockWidget * dock = new FbLogDock(tr("Message log"), this);
  84. dock->setAttribute(Qt::WA_DeleteOnClose);
  85. dock->setFeatures(QDockWidget::AllDockWidgetFeatures);
  86. dock->setWidget(messageEdit);
  87. addDockWidget(Qt::BottomDockWidgetArea, dock);
  88. messageEdit->setMaximumHeight(80);
  89. }
  90. messageEdit->append(message);
  91. }
  92. void FbMainWindow::logShowed()
  93. {
  94. messageEdit->setMaximumHeight(QWIDGETSIZE_MAX);
  95. }
  96. void FbMainWindow::logDestroyed()
  97. {
  98. messageEdit = NULL;
  99. }
  100. void FbMainWindow::treeDestroyed()
  101. {
  102. actionContents->setChecked(false);
  103. dockTree = NULL;
  104. }
  105. void FbMainWindow::imgsDestroyed()
  106. {
  107. actionPictures->setChecked(false);
  108. dockImgs = NULL;
  109. }
  110. bool FbMainWindow::loadXML(const QString &filename)
  111. {
  112. if (!filename.isEmpty()) {
  113. QFile file(filename);
  114. if (file.open(QFile::ReadOnly | QFile::Text)) {
  115. codeEdit->clear();
  116. return codeEdit->read(&file);
  117. }
  118. }
  119. return false;
  120. }
  121. void FbMainWindow::closeEvent(QCloseEvent *event)
  122. {
  123. if (maybeSave()) {
  124. writeSettings();
  125. event->accept();
  126. } else {
  127. event->ignore();
  128. }
  129. }
  130. void FbMainWindow::fileNew()
  131. {
  132. FbMainWindow *other = new FbMainWindow;
  133. other->move(x() + 40, y() + 40);
  134. other->show();
  135. }
  136. void FbMainWindow::fileOpen()
  137. {
  138. QString filename = QFileDialog::getOpenFileName(this, tr("Open file"), QString(), "Fiction book files (*.fb2)");
  139. if (filename.isEmpty()) return;
  140. FbMainWindow * existing = findFbMainWindow(filename);
  141. if (existing) {
  142. existing->show();
  143. existing->raise();
  144. existing->activateWindow();
  145. return;
  146. }
  147. if (textFrame) {
  148. if (isUntitled && !isWindowModified()) {
  149. setCurrentFile(filename);
  150. FbTextPage *page = new FbTextPage(this);
  151. if (page->load(filename, QString())) {
  152. viewText(page);
  153. } else {
  154. delete page;
  155. viewCode();
  156. if (!filename.isEmpty()) loadXML(filename);
  157. }
  158. } else {
  159. FbMainWindow * other = new FbMainWindow(filename, FB2);
  160. other->move(x() + 40, y() + 40);
  161. other->show();
  162. }
  163. } else if (codeEdit) {
  164. if (isUntitled && !isWindowModified()) {
  165. setCurrentFile(filename);
  166. loadXML(filename);
  167. } else {
  168. FbMainWindow * other = new FbMainWindow(filename, XML);
  169. other->move(x() + 40, y() + 40);
  170. other->show();
  171. }
  172. }
  173. }
  174. bool FbMainWindow::fileSave()
  175. {
  176. if (isUntitled) {
  177. return fileSaveAs();
  178. } else {
  179. return saveFile(curFile);
  180. }
  181. }
  182. bool FbMainWindow::fileSaveAs()
  183. {
  184. FbSaveDialog dlg(this, tr("Save As..."));
  185. dlg.selectFile(curFile);
  186. if (!dlg.exec()) return false;
  187. QString fileName = dlg.fileName();
  188. if (fileName.isEmpty()) return false;
  189. return saveFile(fileName, dlg.codec());
  190. }
  191. void FbMainWindow::about()
  192. {
  193. QMessageBox::about(this, tr("About fb2edit"),
  194. tr("The <b>fb2edit</b> is application for editing FB2-files."));
  195. }
  196. void FbMainWindow::documentWasModified()
  197. {
  198. setModified(isSwitched || codeEdit->isModified());
  199. }
  200. void FbMainWindow::cleanChanged(bool clean)
  201. {
  202. setModified(isSwitched || !clean);
  203. }
  204. void FbMainWindow::setModified(bool modified)
  205. {
  206. QFileInfo info = windowFilePath();
  207. QString title = info.fileName();
  208. if (modified) title += QString("[*]");
  209. title += appTitle();
  210. setWindowTitle(title);
  211. setWindowModified(modified);
  212. }
  213. void FbMainWindow::createActions()
  214. {
  215. QAction * act;
  216. QMenu * menu;
  217. QToolBar * tool;
  218. QList<QAction*> actions;
  219. menu = menuBar()->addMenu(tr("&File"));
  220. tool = addToolBar(tr("File"));
  221. tool->setMovable(false);
  222. act = new QAction(FbIcon("document-new"), tr("&New"), this);
  223. act->setPriority(QAction::LowPriority);
  224. act->setShortcuts(QKeySequence::New);
  225. act->setStatusTip(tr("Create a new file"));
  226. connect(act, SIGNAL(triggered()), this, SLOT(fileNew()));
  227. menu->addAction(act);
  228. tool->addAction(act);
  229. act = new QAction(FbIcon("document-open"), tr("&Open..."), this);
  230. act->setShortcuts(QKeySequence::Open);
  231. act->setStatusTip(tr("Open an existing file"));
  232. connect(act, SIGNAL(triggered()), this, SLOT(fileOpen()));
  233. menu->addAction(act);
  234. tool->addAction(act);
  235. act = new QAction(FbIcon("document-save"), tr("&Save"), this);
  236. act->setShortcuts(QKeySequence::Save);
  237. act->setStatusTip(tr("Save the document to disk"));
  238. connect(act, SIGNAL(triggered()), this, SLOT(fileSave()));
  239. menu->addAction(act);
  240. tool->addAction(act);
  241. act = new QAction(FbIcon("document-save-as"), tr("Save &As..."), this);
  242. act->setShortcuts(QKeySequence::SaveAs);
  243. act->setStatusTip(tr("Save the document under a new name"));
  244. connect(act, SIGNAL(triggered()), this, SLOT(fileSaveAs()));
  245. menu->addAction(act);
  246. menu->addSeparator();
  247. act = new QAction(FbIcon("window-close"), tr("&Close"), this);
  248. act->setShortcuts(QKeySequence::Close);
  249. act->setStatusTip(tr("Close this window"));
  250. connect(act, SIGNAL(triggered()), this, SLOT(close()));
  251. menu->addAction(act);
  252. act = new QAction(FbIcon("application-exit"), tr("E&xit"), this);
  253. act->setShortcuts(QKeySequence::Quit);
  254. act->setStatusTip(tr("Exit the application"));
  255. connect(act, SIGNAL(triggered()), qApp, SLOT(closeAllWindows()));
  256. menu->addAction(act);
  257. menuEdit = menu = menuBar()->addMenu(tr("&Edit"));
  258. connect(QApplication::clipboard(), SIGNAL(dataChanged()), this, SLOT(clipboardDataChanged()));
  259. actionUndo = act = new QAction(FbIcon("edit-undo"), tr("&Undo"), this);
  260. act->setPriority(QAction::LowPriority);
  261. act->setShortcut(QKeySequence::Undo);
  262. act->setEnabled(false);
  263. menu->addAction(act);
  264. actionRedo = act = new QAction(FbIcon("edit-redo"), tr("&Redo"), this);
  265. act->setPriority(QAction::LowPriority);
  266. act->setShortcut(QKeySequence::Redo);
  267. act->setEnabled(false);
  268. menu->addAction(act);
  269. menu->addSeparator();
  270. actionCut = act = new QAction(FbIcon("edit-cut"), tr("Cu&t"), this);
  271. act->setShortcutContext(Qt::WidgetShortcut);
  272. act->setPriority(QAction::LowPriority);
  273. act->setShortcuts(QKeySequence::Cut);
  274. act->setStatusTip(tr("Cut the current selection's contents to the clipboard"));
  275. act->setEnabled(false);
  276. menu->addAction(act);
  277. actionCopy = act = new QAction(FbIcon("edit-copy"), tr("&Copy"), this);
  278. act->setShortcutContext(Qt::WidgetShortcut);
  279. act->setPriority(QAction::LowPriority);
  280. act->setShortcuts(QKeySequence::Copy);
  281. act->setStatusTip(tr("Copy the current selection's contents to the clipboard"));
  282. act->setEnabled(false);
  283. menu->addAction(act);
  284. actionPaste = act = new QAction(FbIcon("edit-paste"), tr("&Paste"), this);
  285. act->setShortcutContext(Qt::WidgetShortcut);
  286. act->setPriority(QAction::LowPriority);
  287. act->setShortcuts(QKeySequence::Paste);
  288. act->setStatusTip(tr("Paste the clipboard's contents into the current selection"));
  289. menu->addAction(act);
  290. actionPasteText = act = new QAction(tr("Paste (no style)"), this);
  291. menu->addAction(act);
  292. clipboardDataChanged();
  293. menu->addSeparator();
  294. actionFind = act = new QAction(FbIcon("edit-find"), tr("&Find..."), this);
  295. act->setShortcuts(QKeySequence::Find);
  296. menu->addAction(act);
  297. actionReplace = act = new QAction(FbIcon("edit-find-replace"), tr("&Replace..."), this);
  298. menu->addAction(act);
  299. menu->addSeparator();
  300. act = new QAction(FbIcon("preferences-desktop"), tr("&Settings"), this);
  301. act->setShortcuts(QKeySequence::Preferences);
  302. act->setStatusTip(tr("Application settings"));
  303. connect(act, SIGNAL(triggered()), SLOT(openSettings()));
  304. menu->addAction(act);
  305. menu = menuBar()->addMenu(tr("&Insert", "Main menu"));
  306. actionImage = act = new QAction(FbIcon("insert-image"), tr("&Image"), this);
  307. menu->addAction(act);
  308. actionNote = act = new QAction(FbIcon("insert-text"), tr("&Footnote"), this);
  309. menu->addAction(act);
  310. actionLink = act = new QAction(FbIcon("insert-link"), tr("&Hiperlink"), this);
  311. menu->addAction(act);
  312. menu->addSeparator();
  313. actionBody = act = new QAction(tr("&Body"), this);
  314. menu->addAction(act);
  315. actionSection = act = new QAction(FbIcon("insert-object"), tr("&Section"), this);
  316. menu->addAction(act);
  317. actionTitle = act = new QAction(tr("&Title"), this);
  318. menu->addAction(act);
  319. actionEpigraph = act = new QAction(tr("&Epigraph"), this);
  320. menu->addAction(act);
  321. actionAnnot = act = new QAction(tr("&Annotation"), this);
  322. menu->addAction(act);
  323. actionSubtitle = act = new QAction(tr("&Subtitle"), this);
  324. menu->addAction(act);
  325. actionAuthor = act = new QAction(tr("&Cite"), this);
  326. menu->addAction(act);
  327. actionPoem = act = new QAction(tr("&Poem"), this);
  328. menu->addAction(act);
  329. actionStanza = act = new QAction(tr("&Stanza"), this);
  330. menu->addAction(act);
  331. actionAuthor = act = new QAction(tr("&Author"), this);
  332. menu->addAction(act);
  333. actionDate = act = new QAction(tr("&Date"), this);
  334. menu->addAction(act);
  335. menu->addSeparator();
  336. actionSimpleText = act = new QAction(tr("Simple text"), this);
  337. menu->addAction(act);
  338. actionParaSeparator = act = new QAction(tr("Paragraph"), this);
  339. menu->addAction(act);
  340. actionLineSeparator = act = new QAction(tr("Line end"), this);
  341. menu->addAction(act);
  342. menuText = menu = menuBar()->addMenu(tr("Fo&rmat"));
  343. actionClearFormat = act = new FbTextAction(FbIcon("edit-clear"), tr("Clear format"), QWebPage::RemoveFormat, this);
  344. menu->addAction(act);
  345. menu->addSeparator();
  346. actionTextBold = act = new FbTextAction(FbIcon("format-text-bold"), tr("&Bold"), QWebPage::ToggleBold, this);
  347. act->setShortcuts(QKeySequence::Bold);
  348. act->setCheckable(true);
  349. menu->addAction(act);
  350. actionTextItalic = act = new FbTextAction(FbIcon("format-text-italic"), tr("&Italic"), QWebPage::ToggleItalic, this);
  351. act->setShortcuts(QKeySequence::Italic);
  352. act->setCheckable(true);
  353. menu->addAction(act);
  354. actionTextStrike = act = new FbTextAction(FbIcon("format-text-strikethrough"), tr("&Strikethrough"), QWebPage::ToggleStrikethrough, this);
  355. act->setCheckable(true);
  356. menu->addAction(act);
  357. actionTextSup = act = new FbTextAction(FbIcon("format-text-superscript"), tr("Su&perscript"), QWebPage::ToggleSuperscript, this);
  358. act->setCheckable(true);
  359. menu->addAction(act);
  360. actionTextSub = act = new FbTextAction(FbIcon("format-text-subscript"), tr("Su&bscript"), QWebPage::ToggleSubscript, this);
  361. act->setCheckable(true);
  362. menu->addAction(act);
  363. actionTextCode = act = new QAction(FbIcon("utilities-terminal"), tr("&Code"), this);
  364. act->setCheckable(true);
  365. menu->addAction(act);
  366. menu->addSeparator();
  367. actionSectionAdd = act = new FbTextAction(FbIcon("format-indent-more"), tr("Create section"), QWebPage::ToggleSubscript, this);
  368. menu->addAction(act);
  369. actionSectionDel = act = new FbTextAction(FbIcon("format-indent-less"), tr("Remove section"), QWebPage::ToggleSubscript, this);
  370. menu->addAction(act);
  371. actionTextTitle = act = new FbTextAction(FbIcon("format-justify-center"), tr("Make title"), QWebPage::ToggleSubscript, this);
  372. menu->addAction(act);
  373. menuView = menu = menuBar()->addMenu(tr("&View"));
  374. tool->addSeparator();
  375. QActionGroup * viewGroup = new QActionGroup(this);
  376. act = new QAction(tr("&Text"), this);
  377. act->setCheckable(true);
  378. act->setChecked(true);
  379. connect(act, SIGNAL(triggered()), this, SLOT(viewText()));
  380. viewGroup->addAction(act);
  381. menu->addAction(act);
  382. tool->addAction(act);
  383. act = new QAction(tr("&Head"), this);
  384. act->setCheckable(true);
  385. connect(act, SIGNAL(triggered()), this, SLOT(viewHead()));
  386. viewGroup->addAction(act);
  387. menu->addAction(act);
  388. tool->addAction(act);
  389. act = new QAction(tr("&XML"), this);
  390. act->setCheckable(true);
  391. connect(act, SIGNAL(triggered()), this, SLOT(viewCode()));
  392. viewGroup->addAction(act);
  393. menu->addAction(act);
  394. tool->addAction(act);
  395. #ifdef QT_DEBUG
  396. act = new QAction(tr("&HTML"), this);
  397. act->setCheckable(true);
  398. connect(act, SIGNAL(triggered()), this, SLOT(viewHtml()));
  399. viewGroup->addAction(act);
  400. menu->addAction(act);
  401. #endif // _DEBUG
  402. menu->addSeparator();
  403. actionZoomIn = act = new QAction(FbIcon("zoom-in"), tr("Zoom in"), this);
  404. act->setShortcuts(QKeySequence::ZoomIn);
  405. menu->addAction(act);
  406. actionZoomOut = act = new QAction(FbIcon("zoom-out"), tr("Zoom out"), this);
  407. act->setShortcuts(QKeySequence::ZoomOut);
  408. menu->addAction(act);
  409. actionZoomReset = act = new QAction(FbIcon("zoom-original"), tr("Zoom original"), this);
  410. menu->addAction(act);
  411. menu->addSeparator();
  412. actionContents = act = new QAction(tr("&Contents"), this);
  413. act->setCheckable(true);
  414. connect(act, SIGNAL(triggered()), this, SLOT(viewTree()));
  415. menu->addAction(act);
  416. actionPictures = act = new QAction(tr("&Pictures"), this);
  417. act->setCheckable(true);
  418. connect(act, SIGNAL(triggered()), this, SLOT(viewImgs()));
  419. menu->addAction(act);
  420. actionInspect = act = new QAction(tr("&Web inspector"), this);
  421. act->setCheckable(true);
  422. connect(this, SIGNAL(showInspectorChecked(bool)), actionInspect, SLOT(setChecked(bool)));
  423. menu->addAction(act);
  424. menuBar()->addSeparator();
  425. menu = menuBar()->addMenu(tr("&Help"));
  426. act = new QAction(FbIcon("help-about"), tr("&About"), this);
  427. act->setStatusTip(tr("Show the application's About box"));
  428. connect(act, SIGNAL(triggered()), this, SLOT(about()));
  429. menu->addAction(act);
  430. act = new QAction(tr("About &Qt"), this);
  431. act->setStatusTip(tr("Show the Qt library's About box"));
  432. connect(act, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
  433. menu->addAction(act);
  434. }
  435. void FbMainWindow::openSettings()
  436. {
  437. FbSetupDlg dlg(this);
  438. dlg.exec();
  439. }
  440. void FbMainWindow::createTree()
  441. {
  442. if (textFrame && centralWidget() == textFrame) {
  443. dockTree = new FbDockWidget(tr("Contents"), this);
  444. dockTree->setWidget(new FbTreeWidget(textFrame->view(), this));
  445. connect(dockTree, SIGNAL(visibilityChanged(bool)), actionContents, SLOT(setChecked(bool)));
  446. connect(dockTree, SIGNAL(destroyed()), SLOT(treeDestroyed()));
  447. addDockWidget(Qt::LeftDockWidgetArea, dockTree);
  448. }
  449. }
  450. void FbMainWindow::createImgs()
  451. {
  452. if (textFrame && centralWidget() == textFrame) {
  453. dockImgs = new FbDockWidget(tr("Pictures"), this);
  454. dockImgs->setWidget(new FbListWidget(textFrame->view(), this));
  455. connect(dockImgs, SIGNAL(visibilityChanged(bool)), actionPictures, SLOT(setChecked(bool)));
  456. connect(dockImgs, SIGNAL(destroyed()), SLOT(imgsDestroyed()));
  457. addDockWidget(Qt::RightDockWidgetArea, dockImgs);
  458. }
  459. }
  460. void FbMainWindow::selectionChanged()
  461. {
  462. FbTextEdit *view = textFrame->view();
  463. actionCut->setEnabled(view->actionEnabled(QWebPage::Cut));
  464. actionCopy->setEnabled(view->actionEnabled(QWebPage::Copy));
  465. statusBar()->showMessage(view->page()->status());
  466. }
  467. void FbMainWindow::canUndoChanged(bool canUndo)
  468. {
  469. actionUndo->setEnabled(canUndo);
  470. }
  471. void FbMainWindow::canRedoChanged(bool canRedo)
  472. {
  473. actionRedo->setEnabled(canRedo);
  474. }
  475. void FbMainWindow::undoChanged()
  476. {
  477. actionUndo->setEnabled(textFrame->view()->actionEnabled(QWebPage::Undo));
  478. }
  479. void FbMainWindow::redoChanged()
  480. {
  481. actionRedo->setEnabled(textFrame->view()->actionEnabled(QWebPage::Redo));
  482. }
  483. void FbMainWindow::createStatusBar()
  484. {
  485. statusBar()->showMessage(tr("Ready"));
  486. }
  487. void FbMainWindow::readSettings()
  488. {
  489. QSettings settings;
  490. QPoint pos = settings.value("pos", QPoint(200, 200)).toPoint();
  491. QSize size = settings.value("size", QSize(400, 400)).toSize();
  492. move(pos);
  493. resize(size);
  494. }
  495. void FbMainWindow::writeSettings()
  496. {
  497. QSettings settings;
  498. settings.setValue("pos", pos());
  499. settings.setValue("size", size());
  500. }
  501. bool FbMainWindow::maybeSave()
  502. {
  503. if (textFrame && textFrame->view()->isModified()) {
  504. QMessageBox::StandardButton ret;
  505. ret = QMessageBox::warning(this, qApp->applicationName(),
  506. tr("The document has been modified. Do you want to save your changes?"),
  507. QMessageBox::Save | QMessageBox::Discard
  508. | QMessageBox::Cancel);
  509. if (ret == QMessageBox::Save)
  510. return fileSave();
  511. else if (ret == QMessageBox::Cancel)
  512. return false;
  513. }
  514. return true;
  515. }
  516. bool FbMainWindow::saveFile(const QString &fileName, const QString &codec)
  517. {
  518. QFile file(fileName);
  519. if (!file.open(QFile::WriteOnly | QFile::Text)) {
  520. QMessageBox::warning(this, qApp->applicationName(), tr("Cannot write file %1: %2.").arg(fileName).arg(file.errorString()));
  521. return false;
  522. }
  523. if (textFrame) {
  524. isSwitched = false;
  525. textFrame->view()->save(&file, codec);
  526. setCurrentFile(fileName);
  527. return true;
  528. }
  529. if (codeEdit) {
  530. QTextStream out(&file);
  531. out << codeEdit->toPlainText();
  532. setCurrentFile(fileName);
  533. return true;
  534. }
  535. return false;
  536. }
  537. void FbMainWindow::setCurrentFile(const QString &filename)
  538. {
  539. if (filename.isEmpty()) {
  540. static int sequenceNumber = 1;
  541. curFile = QString("book%1.fb2").arg(sequenceNumber++);
  542. } else {
  543. QFileInfo info = filename;
  544. curFile = info.canonicalFilePath();
  545. }
  546. setWindowFilePath(curFile);
  547. setModified(false);
  548. }
  549. QString FbMainWindow::appTitle() const
  550. {
  551. return QString(" - ") += qApp->applicationName() += QString(" ") += qApp->applicationVersion();
  552. }
  553. FbMainWindow *FbMainWindow::findFbMainWindow(const QString &fileName)
  554. {
  555. QString canonicalFilePath = QFileInfo(fileName).canonicalFilePath();
  556. foreach (QWidget *widget, qApp->topLevelWidgets()) {
  557. FbMainWindow *mainWin = qobject_cast<FbMainWindow *>(widget);
  558. if (mainWin && mainWin->curFile == canonicalFilePath)
  559. return mainWin;
  560. }
  561. return 0;
  562. }
  563. void FbMainWindow::checkScintillaUndo()
  564. {
  565. if (!codeEdit) return;
  566. actionUndo->setEnabled(codeEdit->isUndoAvailable());
  567. actionRedo->setEnabled(codeEdit->isRedoAvailable());
  568. }
  569. void FbMainWindow::createTextToolbar()
  570. {
  571. FbTextEdit * textEdit = textFrame->view();
  572. FbTextPage * textPage = textEdit->page();
  573. connect(textPage->undoStack(), SIGNAL(cleanChanged(bool)), SLOT(cleanChanged(bool)));
  574. connect(textPage->undoStack(), SIGNAL(canUndoChanged(bool)), SLOT(canUndoChanged(bool)));
  575. connect(textPage->undoStack(), SIGNAL(canRedoChanged(bool)), SLOT(canRedoChanged(bool)));
  576. connect(textPage, SIGNAL(selectionChanged()), SLOT(selectionChanged()));
  577. connect(actionUndo, SIGNAL(triggered()), textEdit->pageAction(QWebPage::Undo), SIGNAL(triggered()));
  578. connect(actionRedo, SIGNAL(triggered()), textEdit->pageAction(QWebPage::Redo), SIGNAL(triggered()));
  579. connect(actionCut, SIGNAL(triggered()), textEdit->pageAction(QWebPage::Cut), SIGNAL(triggered()));
  580. connect(actionCopy, SIGNAL(triggered()), textEdit->pageAction(QWebPage::Copy), SIGNAL(triggered()));
  581. connect(actionPaste, SIGNAL(triggered()), textEdit->pageAction(QWebPage::Paste), SIGNAL(triggered()));
  582. connect(actionPasteText, SIGNAL(triggered()), textEdit->pageAction(QWebPage::PasteAndMatchStyle), SIGNAL(triggered()));
  583. connect(actionClearFormat, SIGNAL(triggered()), textEdit->pageAction(QWebPage::RemoveFormat), SIGNAL(triggered()));
  584. connect(actionTextBold, SIGNAL(triggered()), textEdit->pageAction(QWebPage::ToggleBold), SIGNAL(triggered()));
  585. connect(actionTextItalic, SIGNAL(triggered()), textEdit->pageAction(QWebPage::ToggleItalic), SIGNAL(triggered()));
  586. connect(actionTextStrike, SIGNAL(triggered()), textEdit->pageAction(QWebPage::ToggleStrikethrough), SIGNAL(triggered()));
  587. connect(actionTextSub, SIGNAL(triggered()), textEdit->pageAction(QWebPage::ToggleSubscript), SIGNAL(triggered()));
  588. connect(actionTextSup, SIGNAL(triggered()), textEdit->pageAction(QWebPage::ToggleSuperscript), SIGNAL(triggered()));
  589. connect(textEdit->pageAction(QWebPage::RemoveFormat), SIGNAL(changed()), actionClearFormat, SLOT(updateEnabled()));
  590. connect(textEdit->pageAction(QWebPage::ToggleBold), SIGNAL(changed()), actionTextBold, SLOT(updateChecked()));
  591. connect(textEdit->pageAction(QWebPage::ToggleItalic), SIGNAL(changed()), actionTextItalic, SLOT(updateChecked()));
  592. connect(textEdit->pageAction(QWebPage::ToggleStrikethrough), SIGNAL(changed()), actionTextStrike, SLOT(updateChecked()));
  593. connect(textEdit->pageAction(QWebPage::ToggleSubscript), SIGNAL(changed()), actionTextSub, SLOT(updateChecked()));
  594. connect(textEdit->pageAction(QWebPage::ToggleSuperscript), SIGNAL(changed()), actionTextSup, SLOT(updateChecked()));
  595. connect(actionFind, SIGNAL(triggered()), textEdit, SLOT(find()));
  596. connect(actionImage, SIGNAL(triggered()), textEdit, SLOT(insertImage()));
  597. connect(actionNote, SIGNAL(triggered()), textEdit, SLOT(insertNote()));
  598. connect(actionLink, SIGNAL(triggered()), textEdit, SLOT(insertLink()));
  599. connect(actionTitle, SIGNAL(triggered()), textPage, SLOT(insertTitle()));
  600. connect(actionAnnot, SIGNAL(triggered()), textPage, SLOT(insertAnnot()));
  601. connect(actionAuthor, SIGNAL(triggered()), textPage, SLOT(insertAuthor()));
  602. connect(actionEpigraph, SIGNAL(triggered()), textPage, SLOT(insertEpigraph()));
  603. connect(actionSubtitle, SIGNAL(triggered()), textPage, SLOT(insertSubtitle()));
  604. connect(actionSection, SIGNAL(triggered()), textPage, SLOT(insertSection()));
  605. connect(actionStanza, SIGNAL(triggered()), textPage, SLOT(insertStanza()));
  606. connect(actionPoem, SIGNAL(triggered()), textPage, SLOT(insertPoem()));
  607. connect(actionDate, SIGNAL(triggered()), textPage, SLOT(insertDate()));
  608. connect(actionBody, SIGNAL(triggered()), textPage, SLOT(insertBody()));
  609. connect(actionSimpleText, SIGNAL(triggered()), textPage, SLOT(insertText()));
  610. connect(actionParaSeparator, SIGNAL(triggered()), textEdit->pageAction(QWebPage::InsertParagraphSeparator), SIGNAL(triggered()));
  611. connect(actionLineSeparator, SIGNAL(triggered()), textEdit->pageAction(QWebPage::InsertLineSeparator), SIGNAL(triggered()));
  612. connect(actionSectionAdd, SIGNAL(triggered()), textPage, SLOT(createSection()));
  613. connect(actionSectionDel, SIGNAL(triggered()), textPage, SLOT(deleteSection()));
  614. connect(actionTextTitle, SIGNAL(triggered()), textPage, SLOT(createTitle()));
  615. connect(actionZoomIn, SIGNAL(triggered()), textEdit, SLOT(zoomIn()));
  616. connect(actionZoomOut, SIGNAL(triggered()), textEdit, SLOT(zoomOut()));
  617. connect(actionZoomReset, SIGNAL(triggered()), textEdit, SLOT(zoomReset()));
  618. FB2DELETE(toolEdit);
  619. QToolBar *tool = toolEdit = addToolBar(tr("Edit"));
  620. tool->setMovable(false);
  621. tool->addSeparator();
  622. textEdit->addTools(tool);
  623. tool->addSeparator();
  624. tool->addAction(actionSectionAdd);
  625. tool->addAction(actionSectionDel);
  626. tool->addAction(actionTextTitle);
  627. tool->addSeparator();
  628. tool->addAction(actionImage);
  629. tool->addAction(actionNote);
  630. tool->addAction(actionLink);
  631. tool->addAction(actionSection);
  632. }
  633. void FbMainWindow::viewText(FbTextPage *page)
  634. {
  635. if (textFrame && centralWidget() == textFrame) return;
  636. if (textFrame) textFrame->hideInspector();
  637. if (codeEdit) {
  638. QString xml = codeEdit->text();
  639. page = new FbTextPage(this);
  640. if (!page->load(QString(), xml)) {
  641. delete page;
  642. return;
  643. }
  644. isSwitched = true;
  645. }
  646. FB2DELETE(codeEdit);
  647. FB2DELETE(headTree);
  648. if (textFrame) {
  649. createTextToolbar();
  650. } else {
  651. textFrame = new FbTextFrame(this, actionInspect);
  652. }
  653. setCentralWidget(textFrame);
  654. FbTextEdit *textEdit = textFrame->view();
  655. if (page) {
  656. page->setParent(textEdit);
  657. textEdit->setPage(page);
  658. }
  659. connect(textEdit, SIGNAL(loadFinished(bool)), SLOT(createTextToolbar()));
  660. connect(textEdit->pageAction(QWebPage::Undo), SIGNAL(changed()), SLOT(undoChanged()));
  661. connect(textEdit->pageAction(QWebPage::Redo), SIGNAL(changed()), SLOT(redoChanged()));
  662. actionContents->setEnabled(true);
  663. actionPictures->setEnabled(true);
  664. actionInspect->setEnabled(true);
  665. textEdit->setFocus();
  666. viewTree();
  667. }
  668. void FbMainWindow::viewHead()
  669. {
  670. if (headTree && centralWidget() == headTree) return;
  671. if (textFrame) textFrame->hideInspector();
  672. FbTextPage *page = 0;
  673. if (codeEdit) {
  674. QString xml = codeEdit->text();
  675. page = new FbTextPage(this);
  676. if (!page->load(QString(), xml)) {
  677. delete page;
  678. return;
  679. }
  680. isSwitched = true;
  681. }
  682. FB2DELETE(dockTree);
  683. FB2DELETE(dockImgs);
  684. FB2DELETE(codeEdit);
  685. FB2DELETE(toolEdit);
  686. if (!textFrame) {
  687. textFrame = new FbTextFrame(this, actionInspect);
  688. FbTextEdit *textEdit = textFrame->view();
  689. if (page) {
  690. page->setParent(textEdit);
  691. textEdit->setPage(page);
  692. }
  693. }
  694. if (!headTree) {
  695. headTree = new FbHeadView(textFrame->view(), this);
  696. connect(headTree, SIGNAL(status(QString)), this, SLOT(status(QString)));
  697. }
  698. this->setFocus();
  699. textFrame->setParent(NULL);
  700. setCentralWidget(headTree);
  701. textFrame->setParent(this);
  702. headTree->updateTree();
  703. headTree->setFocus();
  704. if (textFrame) {
  705. actionUndo->disconnect();
  706. actionRedo->disconnect();
  707. actionCut->disconnect();
  708. actionCopy->disconnect();
  709. actionPaste->disconnect();
  710. actionTextBold->disconnect();
  711. actionTextItalic->disconnect();
  712. actionTextStrike->disconnect();
  713. actionTextSub->disconnect();
  714. actionTextSup->disconnect();
  715. }
  716. FB2DELETE(toolEdit);
  717. toolEdit = addToolBar(tr("Edit"));
  718. headTree->initToolbar(*toolEdit);
  719. toolEdit->addSeparator();
  720. toolEdit->setMovable(false);
  721. actionContents->setEnabled(false);
  722. actionPictures->setEnabled(false);
  723. actionInspect->setEnabled(true);
  724. }
  725. void FbMainWindow::viewCode()
  726. {
  727. if (codeEdit && centralWidget() == codeEdit) return;
  728. bool load = false;
  729. QByteArray xml;
  730. if (textFrame) {
  731. textFrame->view()->save(&xml);
  732. isSwitched = true;
  733. load = true;
  734. }
  735. FB2DELETE(textFrame);
  736. FB2DELETE(dockTree);
  737. FB2DELETE(dockImgs);
  738. FB2DELETE(headTree);
  739. if (!codeEdit) {
  740. codeEdit = new FbCodeEdit;
  741. }
  742. if (load) codeEdit->load(xml);
  743. setCentralWidget(codeEdit);
  744. codeEdit->setFocus();
  745. FB2DELETE(toolEdit);
  746. QToolBar *tool = toolEdit = addToolBar(tr("Edit"));
  747. tool->addSeparator();
  748. tool->addAction(actionUndo);
  749. tool->addAction(actionRedo);
  750. tool->addSeparator();
  751. tool->addAction(actionCut);
  752. tool->addAction(actionCopy);
  753. tool->addAction(actionPaste);
  754. tool->addSeparator();
  755. tool->addAction(actionZoomIn);
  756. tool->addAction(actionZoomOut);
  757. tool->addAction(actionZoomReset);
  758. tool->setMovable(false);
  759. connect(codeEdit, SIGNAL(textChanged()), this, SLOT(documentWasModified()));
  760. connect(codeEdit, SIGNAL(textChanged()), this, SLOT(checkScintillaUndo()));
  761. connect(codeEdit, SIGNAL(copyAvailable(bool)), actionCut, SLOT(setEnabled(bool)));
  762. connect(codeEdit, SIGNAL(copyAvailable(bool)), actionCopy, SLOT(setEnabled(bool)));
  763. connect(actionUndo, SIGNAL(triggered()), codeEdit, SLOT(undo()));
  764. connect(actionRedo, SIGNAL(triggered()), codeEdit, SLOT(redo()));
  765. connect(actionCut, SIGNAL(triggered()), codeEdit, SLOT(cut()));
  766. connect(actionCopy, SIGNAL(triggered()), codeEdit, SLOT(copy()));
  767. connect(actionPaste, SIGNAL(triggered()), codeEdit, SLOT(paste()));
  768. connect(actionFind, SIGNAL(triggered()), codeEdit, SLOT(find()));
  769. connect(actionZoomIn, SIGNAL(triggered()), codeEdit, SLOT(zoomIn()));
  770. connect(actionZoomOut, SIGNAL(triggered()), codeEdit, SLOT(zoomOut()));
  771. connect(actionZoomReset, SIGNAL(triggered()), codeEdit, SLOT(zoomReset()));
  772. actionContents->setEnabled(false);
  773. actionPictures->setEnabled(false);
  774. actionInspect->setEnabled(false);
  775. }
  776. void FbMainWindow::viewHtml()
  777. {
  778. if (codeEdit && centralWidget() == codeEdit) return;
  779. if (!textFrame) return;
  780. QString html = textFrame->view()->page()->mainFrame()->toHtml();
  781. isSwitched = true;
  782. FB2DELETE(textFrame);
  783. FB2DELETE(dockTree);
  784. FB2DELETE(dockImgs);
  785. FB2DELETE(headTree);
  786. if (!codeEdit) {
  787. codeEdit = new FbCodeEdit;
  788. }
  789. codeEdit->setPlainText(html);
  790. setCentralWidget(codeEdit);
  791. codeEdit->setFocus();
  792. FB2DELETE(toolEdit);
  793. QToolBar *tool = toolEdit = addToolBar(tr("Edit"));
  794. tool->addSeparator();
  795. tool->addAction(actionUndo);
  796. tool->addAction(actionRedo);
  797. tool->addSeparator();
  798. tool->addAction(actionCut);
  799. tool->addAction(actionCopy);
  800. tool->addAction(actionPaste);
  801. tool->addSeparator();
  802. tool->addAction(actionZoomIn);
  803. tool->addAction(actionZoomOut);
  804. tool->addAction(actionZoomReset);
  805. tool->setMovable(false);
  806. connect(codeEdit, SIGNAL(textChanged()), this, SLOT(documentWasModified()));
  807. connect(codeEdit, SIGNAL(textChanged()), this, SLOT(checkScintillaUndo()));
  808. connect(codeEdit, SIGNAL(copyAvailable(bool)), actionCut, SLOT(setEnabled(bool)));
  809. connect(codeEdit, SIGNAL(copyAvailable(bool)), actionCopy, SLOT(setEnabled(bool)));
  810. connect(actionUndo, SIGNAL(triggered()), codeEdit, SLOT(undo()));
  811. connect(actionRedo, SIGNAL(triggered()), codeEdit, SLOT(redo()));
  812. connect(actionCut, SIGNAL(triggered()), codeEdit, SLOT(cut()));
  813. connect(actionCopy, SIGNAL(triggered()), codeEdit, SLOT(copy()));
  814. connect(actionPaste, SIGNAL(triggered()), codeEdit, SLOT(paste()));
  815. connect(actionFind, SIGNAL(triggered()), codeEdit, SLOT(find()));
  816. connect(actionZoomIn, SIGNAL(triggered()), codeEdit, SLOT(zoomIn()));
  817. connect(actionZoomOut, SIGNAL(triggered()), codeEdit, SLOT(zoomOut()));
  818. connect(actionZoomReset, SIGNAL(triggered()), codeEdit, SLOT(zoomReset()));
  819. actionContents->setEnabled(false);
  820. actionPictures->setEnabled(false);
  821. actionInspect->setEnabled(false);
  822. }
  823. void FbMainWindow::viewTree()
  824. {
  825. if (dockTree) dockTree->deleteLater(); else createTree();
  826. }
  827. void FbMainWindow::viewImgs()
  828. {
  829. if (dockImgs) dockImgs->deleteLater(); else createImgs();
  830. }
  831. void FbMainWindow::clipboardDataChanged()
  832. {
  833. if (const QMimeData *md = QApplication::clipboard()->mimeData()) {
  834. actionPaste->setEnabled(md->hasText());
  835. actionPasteText->setEnabled(md->hasText());
  836. }
  837. }
  838. void FbMainWindow::status(const QString &text)
  839. {
  840. statusBar()->showMessage(text);
  841. }