veditarea.cpp 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. #include <QtWidgets>
  2. #include "veditarea.h"
  3. #include "veditwindow.h"
  4. #include "vedittab.h"
  5. #include "vnote.h"
  6. #include "vconfigmanager.h"
  7. VEditArea::VEditArea(VNote *vnote, QWidget *parent)
  8. : QWidget(parent), vnote(vnote), curWindowIndex(0)
  9. {
  10. setupUI();
  11. }
  12. void VEditArea::setupUI()
  13. {
  14. splitter = new QSplitter(this);
  15. // Add a window
  16. insertSplitWindow(0);
  17. setCurrentWindow(0, true);
  18. QHBoxLayout *mainLayout = new QHBoxLayout();
  19. mainLayout->addWidget(splitter);
  20. mainLayout->setContentsMargins(0, 0, 0, 0);
  21. setLayout(mainLayout);
  22. }
  23. void VEditArea::insertSplitWindow(int idx)
  24. {
  25. VEditWindow *win = new VEditWindow(vnote);
  26. splitter->insertWidget(idx, win);
  27. connect(win, &VEditWindow::tabStatusChanged,
  28. this, &VEditArea::curTabStatusChanged);
  29. connect(win, &VEditWindow::requestSplitWindow,
  30. this, &VEditArea::handleSplitWindowRequest);
  31. connect(win, &VEditWindow::requestRemoveSplit,
  32. this, &VEditArea::handleRemoveSplitRequest);
  33. connect(win, &VEditWindow::getFocused,
  34. this, &VEditArea::handleWindowFocused);
  35. connect(win, &VEditWindow::outlineChanged,
  36. this, &VEditArea::handleOutlineChanged);
  37. connect(win, &VEditWindow::curHeaderChanged,
  38. this, &VEditArea::handleCurHeaderChanged);
  39. int nrWin = splitter->count();
  40. if (nrWin == 1) {
  41. // Disable removing split
  42. win->setRemoveSplitEnable(false);
  43. } else {
  44. // Enable removing split
  45. for (int i = 0; i < nrWin; ++i) {
  46. getWindow(i)->setRemoveSplitEnable(true);
  47. }
  48. }
  49. }
  50. void VEditArea::removeSplitWindow(VEditWindow *win)
  51. {
  52. if (!win) {
  53. return;
  54. }
  55. win->hide();
  56. // Should be deleted later
  57. win->deleteLater();
  58. int nrWin = splitter->count();
  59. if (nrWin == 2) {
  60. // Disable removing split
  61. getWindow(0)->setRemoveSplitEnable(false);
  62. getWindow(1)->setRemoveSplitEnable(false);
  63. } else {
  64. // Enable removing split
  65. for (int i = 0; i < nrWin; ++i) {
  66. getWindow(i)->setRemoveSplitEnable(true);
  67. }
  68. }
  69. }
  70. // A given file can be opened in multiple split windows. A given file could be
  71. // opened at most in one tab inside a window.
  72. void VEditArea::openFile(QJsonObject fileJson)
  73. {
  74. if (fileJson.isEmpty()) {
  75. return;
  76. }
  77. QString notebook = fileJson["notebook"].toString();
  78. QString relativePath = fileJson["relative_path"].toString();
  79. int mode = OpenFileMode::Read;
  80. if (fileJson.contains("mode")) {
  81. mode = fileJson["mode"].toInt();
  82. }
  83. qDebug() << "open notebook" << notebook << "path" << relativePath << mode;
  84. // Find if it has been opened already
  85. int winIdx, tabIdx;
  86. bool setFocus = false;
  87. auto tabs = findTabsByFile(notebook, relativePath);
  88. if (!tabs.empty()) {
  89. // Current window first
  90. winIdx = tabs[0].first;
  91. tabIdx = tabs[0].second;
  92. for (int i = 0; i < tabs.size(); ++i) {
  93. if (tabs[i].first == curWindowIndex) {
  94. winIdx = tabs[i].first;
  95. tabIdx = tabs[i].second;
  96. break;
  97. }
  98. }
  99. setFocus = true;
  100. goto out;
  101. }
  102. // Open it in current window
  103. winIdx = curWindowIndex;
  104. tabIdx = openFileInWindow(winIdx, notebook, relativePath, mode);
  105. out:
  106. setCurrentTab(winIdx, tabIdx, setFocus);
  107. }
  108. QVector<QPair<int, int> > VEditArea::findTabsByFile(const QString &notebook, const QString &relativePath)
  109. {
  110. QVector<QPair<int, int> > tabs;
  111. int nrWin = splitter->count();
  112. for (int winIdx = 0; winIdx < nrWin; ++winIdx) {
  113. VEditWindow *win = getWindow(winIdx);
  114. int tabIdx = win->findTabByFile(notebook, relativePath);
  115. if (tabIdx != -1) {
  116. QPair<int, int> match;
  117. match.first = winIdx;
  118. match.second = tabIdx;
  119. tabs.append(match);
  120. }
  121. }
  122. return tabs;
  123. }
  124. int VEditArea::openFileInWindow(int windowIndex, const QString &notebook, const QString &relativePath,
  125. int mode)
  126. {
  127. Q_ASSERT(windowIndex < splitter->count());
  128. VEditWindow *win = getWindow(windowIndex);
  129. return win->openFile(notebook, relativePath, mode);
  130. }
  131. void VEditArea::setCurrentTab(int windowIndex, int tabIndex, bool setFocus)
  132. {
  133. VEditWindow *win = getWindow(windowIndex);
  134. win->setCurrentIndex(tabIndex);
  135. setCurrentWindow(windowIndex, setFocus);
  136. }
  137. void VEditArea::setCurrentWindow(int windowIndex, bool setFocus)
  138. {
  139. if (curWindowIndex == windowIndex) {
  140. goto out;
  141. }
  142. qDebug() << "current window" << windowIndex;
  143. curWindowIndex = windowIndex;
  144. if (setFocus) {
  145. getWindow(windowIndex)->focusWindow();
  146. }
  147. out:
  148. // Update status
  149. updateWindowStatus();
  150. }
  151. void VEditArea::updateWindowStatus()
  152. {
  153. VEditWindow *win = getWindow(curWindowIndex);
  154. win->requestUpdateTabStatus();
  155. win->requestUpdateOutline();
  156. win->requestUpdateCurHeader();
  157. }
  158. bool VEditArea::closeFile(QJsonObject fileJson)
  159. {
  160. if (fileJson.isEmpty()) {
  161. return true;
  162. }
  163. QString notebook = fileJson["notebook"].toString();
  164. QString relativePath = fileJson["relative_path"].toString();
  165. bool isForced = fileJson["is_forced"].toBool();
  166. int nrWin = splitter->count();
  167. bool ret = false;
  168. for (int i = 0; i < nrWin; ++i) {
  169. VEditWindow *win = getWindow(i);
  170. ret = ret || win->closeFile(notebook, relativePath, isForced);
  171. }
  172. return ret;
  173. }
  174. void VEditArea::editFile()
  175. {
  176. VEditWindow *win = getWindow(curWindowIndex);
  177. win->editFile();
  178. }
  179. void VEditArea::saveFile()
  180. {
  181. VEditWindow *win = getWindow(curWindowIndex);
  182. win->saveFile();
  183. }
  184. void VEditArea::readFile()
  185. {
  186. VEditWindow *win = getWindow(curWindowIndex);
  187. win->readFile();
  188. }
  189. void VEditArea::saveAndReadFile()
  190. {
  191. VEditWindow *win = getWindow(curWindowIndex);
  192. win->saveAndReadFile();
  193. }
  194. void VEditArea::handleNotebookRenamed(const QVector<VNotebook> &notebooks,
  195. const QString &oldName, const QString &newName)
  196. {
  197. int nrWin = splitter->count();
  198. for (int i = 0; i < nrWin; ++i) {
  199. VEditWindow *win = getWindow(i);
  200. win->handleNotebookRenamed(notebooks, oldName, newName);
  201. }
  202. updateWindowStatus();
  203. }
  204. void VEditArea::handleDirectoryRenamed(const QString &notebook, const QString &oldRelativePath,
  205. const QString &newRelativePath)
  206. {
  207. int nrWin = splitter->count();
  208. for (int i = 0; i < nrWin; ++i) {
  209. VEditWindow *win = getWindow(i);
  210. win->handleDirectoryRenamed(notebook, oldRelativePath, newRelativePath);
  211. }
  212. updateWindowStatus();
  213. }
  214. void VEditArea::handleFileRenamed(const QString &notebook,
  215. const QString &oldRelativePath, const QString &newRelativePath)
  216. {
  217. int nrWin = splitter->count();
  218. for (int i = 0; i < nrWin; ++i) {
  219. VEditWindow *win = getWindow(i);
  220. win->handleFileRenamed(notebook, oldRelativePath, newRelativePath);
  221. }
  222. updateWindowStatus();
  223. }
  224. void VEditArea::handleSplitWindowRequest(VEditWindow *curWindow)
  225. {
  226. if (!curWindow) {
  227. return;
  228. }
  229. int idx = splitter->indexOf(curWindow);
  230. qDebug() << "window" << idx << "requests split itself";
  231. insertSplitWindow(++idx);
  232. setCurrentWindow(idx, true);
  233. }
  234. void VEditArea::handleRemoveSplitRequest(VEditWindow *curWindow)
  235. {
  236. if (!curWindow) {
  237. return;
  238. }
  239. int idx = splitter->indexOf(curWindow);
  240. removeSplitWindow(curWindow);
  241. if (idx >= splitter->count()) {
  242. idx = splitter->count() - 1;
  243. }
  244. // At least one split window left
  245. Q_ASSERT(idx >= 0);
  246. setCurrentWindow(idx, true);
  247. }
  248. void VEditArea::mousePressEvent(QMouseEvent *event)
  249. {
  250. return;
  251. qDebug() << "VEditArea press event" << event;
  252. QPoint pos = event->pos();
  253. int nrWin = splitter->count();
  254. for (int i = 0; i < nrWin; ++i) {
  255. VEditWindow *win = getWindow(i);
  256. if (win->geometry().contains(pos, true)) {
  257. setCurrentWindow(i, true);
  258. break;
  259. }
  260. }
  261. QWidget::mousePressEvent(event);
  262. }
  263. void VEditArea::handleWindowFocused()
  264. {
  265. QObject *winObject = sender();
  266. int nrWin = splitter->count();
  267. for (int i = 0; i < nrWin; ++i) {
  268. if (splitter->widget(i) == winObject) {
  269. setCurrentWindow(i, false);
  270. break;
  271. }
  272. }
  273. }
  274. void VEditArea::handleOutlineChanged(const VToc &toc)
  275. {
  276. QObject *winObject = sender();
  277. if (splitter->widget(curWindowIndex) == winObject) {
  278. emit outlineChanged(toc);
  279. }
  280. }
  281. void VEditArea::handleCurHeaderChanged(const VAnchor &anchor)
  282. {
  283. QObject *winObject = sender();
  284. if (splitter->widget(curWindowIndex) == winObject) {
  285. emit curHeaderChanged(anchor);
  286. }
  287. }
  288. void VEditArea::handleOutlineItemActivated(const VAnchor &anchor)
  289. {
  290. // Notice current window
  291. getWindow(curWindowIndex)->scrollCurTab(anchor);
  292. }
  293. bool VEditArea::isFileOpened(const QString &notebook, const QString &relativePath)
  294. {
  295. return !findTabsByFile(notebook, relativePath).isEmpty();
  296. }