vmainwindow.cpp 115 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457
  1. #include <QtWidgets>
  2. #include <QList>
  3. #include <QPrinter>
  4. #include <QPrintDialog>
  5. #include <QPainter>
  6. #include "vmainwindow.h"
  7. #include "vdirectorytree.h"
  8. #include "vnote.h"
  9. #include "vfilelist.h"
  10. #include "vconfigmanager.h"
  11. #include "utils/vutils.h"
  12. #include "veditarea.h"
  13. #include "voutline.h"
  14. #include "vnotebookselector.h"
  15. #include "dialog/vfindreplacedialog.h"
  16. #include "dialog/vsettingsdialog.h"
  17. #include "vcaptain.h"
  18. #include "vedittab.h"
  19. #include "vwebview.h"
  20. #include "vexporter.h"
  21. #include "vmdtab.h"
  22. #include "vvimindicator.h"
  23. #include "vvimcmdlineedit.h"
  24. #include "vtabindicator.h"
  25. #include "dialog/vupdater.h"
  26. #include "vorphanfile.h"
  27. #include "dialog/vorphanfileinfodialog.h"
  28. #include "vsingleinstanceguard.h"
  29. #include "vnotefile.h"
  30. #include "vbuttonwithwidget.h"
  31. #include "vattachmentlist.h"
  32. #include "vfilesessioninfo.h"
  33. #include "vsnippetlist.h"
  34. #include "vtoolbox.h"
  35. #include "vbuttonmenuitem.h"
  36. #include "vpalette.h"
  37. #include "utils/viconutils.h"
  38. #include "dialog/vtipsdialog.h"
  39. #include "vcart.h"
  40. #include "dialog/vexportdialog.h"
  41. #include "vsearcher.h"
  42. #include "vuniversalentry.h"
  43. #include "vsearchue.h"
  44. #include "voutlineue.h"
  45. #include "vhelpue.h"
  46. #include "vlistfolderue.h"
  47. #include "dialog/vfixnotebookdialog.h"
  48. #include "vhistorylist.h"
  49. #include "vexplorer.h"
  50. #include "vlistue.h"
  51. #include "vtagexplorer.h"
  52. #include "vmdeditor.h"
  53. extern VConfigManager *g_config;
  54. extern VPalette *g_palette;
  55. VMainWindow *g_mainWin;
  56. VNote *g_vnote;
  57. VWebUtils *g_webUtils;
  58. const int VMainWindow::c_sharedMemTimerInterval = 1000;
  59. #if defined(QT_NO_DEBUG)
  60. extern QFile g_logFile;
  61. #endif
  62. #define COLOR_PIXMAP_ICON_SIZE 64
  63. enum NaviBoxIndex
  64. {
  65. NotebookPanel = 0,
  66. HistoryList,
  67. Explorer,
  68. TagExplorer
  69. };
  70. VMainWindow::VMainWindow(VSingleInstanceGuard *p_guard, QWidget *p_parent)
  71. : QMainWindow(p_parent),
  72. m_guard(p_guard),
  73. m_windowOldState(Qt::WindowNoState),
  74. m_requestQuit(false),
  75. m_printer(NULL),
  76. m_ue(NULL)
  77. {
  78. qsrand(QDateTime::currentDateTime().toTime_t());
  79. g_mainWin = this;
  80. setWindowIcon(QIcon(":/resources/icons/vnote.ico"));
  81. vnote = new VNote(this);
  82. g_vnote = vnote;
  83. m_webUtils.init();
  84. g_webUtils = &m_webUtils;
  85. initCaptain();
  86. setupUI();
  87. initMenuBar();
  88. initToolBar();
  89. initShortcuts();
  90. initDockWindows();
  91. int state = g_config->getPanelViewState();
  92. if (state < 0 || state >= (int)PanelViewState::Invalid) {
  93. state = (int)PanelViewState::VerticalMode;
  94. }
  95. changePanelView((PanelViewState)state);
  96. restoreStateAndGeometry();
  97. setContextMenuPolicy(Qt::NoContextMenu);
  98. m_notebookSelector->update();
  99. initSharedMemoryWatcher();
  100. initUpdateTimer();
  101. registerCaptainAndNavigationTargets();
  102. }
  103. void VMainWindow::initSharedMemoryWatcher()
  104. {
  105. m_sharedMemTimer = new QTimer(this);
  106. m_sharedMemTimer->setSingleShot(false);
  107. m_sharedMemTimer->setInterval(c_sharedMemTimerInterval);
  108. connect(m_sharedMemTimer, &QTimer::timeout,
  109. this, &VMainWindow::checkSharedMemory);
  110. m_sharedMemTimer->start();
  111. }
  112. void VMainWindow::initCaptain()
  113. {
  114. // VCaptain should be visible to accpet key focus. But VCaptain
  115. // may hide other widgets.
  116. m_captain = new VCaptain(this);
  117. connect(m_captain, &VCaptain::captainModeChanged,
  118. this, [this](bool p_captainMode) {
  119. static QString normalStyle = m_avatarBtn->styleSheet();
  120. static QString captainStyle = QString("color: %1; background: %2;")
  121. .arg(g_palette->color("avatar_captain_mode_fg"))
  122. .arg(g_palette->color("avatar_captain_mode_bg"));
  123. if (p_captainMode) {
  124. m_avatarBtn->setStyleSheet(captainStyle);
  125. } else {
  126. m_avatarBtn->setStyleSheet(normalStyle);
  127. }
  128. });
  129. }
  130. void VMainWindow::registerCaptainAndNavigationTargets()
  131. {
  132. m_captain->registerNavigationTarget(m_naviBox);
  133. m_captain->registerNavigationTarget(m_notebookSelector);
  134. m_captain->registerNavigationTarget(m_dirTree);
  135. m_captain->registerNavigationTarget(m_fileList);
  136. m_captain->registerNavigationTarget(m_historyList);
  137. m_tagExplorer->registerNavigationTarget();
  138. m_captain->registerNavigationTarget(m_editArea);
  139. m_tabIndicator->registerNavigationTarget();
  140. m_captain->registerNavigationTarget(m_toolBox);
  141. m_captain->registerNavigationTarget(outline);
  142. m_captain->registerNavigationTarget(m_snippetList);
  143. m_captain->registerNavigationTarget(m_cart);
  144. m_captain->registerNavigationTarget(m_searcher);
  145. // Register Captain mode targets.
  146. m_captain->registerCaptainTarget(tr("AttachmentList"),
  147. g_config->getCaptainShortcutKeySequence("AttachmentList"),
  148. this,
  149. showAttachmentListByCaptain);
  150. m_captain->registerCaptainTarget(tr("LocateCurrentFile"),
  151. g_config->getCaptainShortcutKeySequence("LocateCurrentFile"),
  152. this,
  153. locateCurrentFileByCaptain);
  154. m_captain->registerCaptainTarget(tr("ExpandMode"),
  155. g_config->getCaptainShortcutKeySequence("ExpandMode"),
  156. this,
  157. toggleExpandModeByCaptain);
  158. m_captain->registerCaptainTarget(tr("DiscardAndRead"),
  159. g_config->getCaptainShortcutKeySequence("DiscardAndRead"),
  160. this,
  161. discardAndReadByCaptain);
  162. m_captain->registerCaptainTarget(tr("ToolBar"),
  163. g_config->getCaptainShortcutKeySequence("ToolBar"),
  164. this,
  165. toggleToolBarByCaptain);
  166. m_captain->registerCaptainTarget(tr("ToolsDock"),
  167. g_config->getCaptainShortcutKeySequence("ToolsDock"),
  168. this,
  169. toggleToolsDockByCaptain);
  170. m_captain->registerCaptainTarget(tr("SearchDock"),
  171. g_config->getCaptainShortcutKeySequence("SearchDock"),
  172. this,
  173. toggleSearchDockByCaptain);
  174. m_captain->registerCaptainTarget(tr("CloseNote"),
  175. g_config->getCaptainShortcutKeySequence("CloseNote"),
  176. this,
  177. closeFileByCaptain);
  178. m_captain->registerCaptainTarget(tr("ShortcutsHelp"),
  179. g_config->getCaptainShortcutKeySequence("ShortcutsHelp"),
  180. this,
  181. shortcutsHelpByCaptain);
  182. m_captain->registerCaptainTarget(tr("FlushLogFile"),
  183. g_config->getCaptainShortcutKeySequence("FlushLogFile"),
  184. this,
  185. flushLogFileByCaptain);
  186. m_captain->registerCaptainTarget(tr("Export"),
  187. g_config->getCaptainShortcutKeySequence("Export"),
  188. this,
  189. exportByCaptain);
  190. m_captain->registerCaptainTarget(tr("FocusEditArea"),
  191. g_config->getCaptainShortcutKeySequence("FocusEditArea"),
  192. this,
  193. focusEditAreaByCaptain);
  194. }
  195. void VMainWindow::setupUI()
  196. {
  197. setupNaviBox();
  198. m_editArea = new VEditArea();
  199. m_editArea->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
  200. m_findReplaceDialog = m_editArea->getFindReplaceDialog();
  201. m_fileList->setEditArea(m_editArea);
  202. m_dirTree->setEditArea(m_editArea);
  203. connect(m_editArea, &VEditArea::fileClosed,
  204. m_historyList, &VHistoryList::addFile);
  205. // Main Splitter
  206. m_mainSplitter = new QSplitter();
  207. m_mainSplitter->setObjectName("MainSplitter");
  208. m_mainSplitter->addWidget(m_naviBox);
  209. m_mainSplitter->addWidget(m_editArea);
  210. m_mainSplitter->setStretchFactor(0, 0);
  211. m_mainSplitter->setStretchFactor(1, 1);
  212. connect(m_dirTree, &VDirectoryTree::directoryUpdated,
  213. m_editArea, &VEditArea::handleDirectoryUpdated);
  214. connect(m_notebookSelector, &VNotebookSelector::notebookUpdated,
  215. m_editArea, &VEditArea::handleNotebookUpdated);
  216. connect(m_notebookSelector, &VNotebookSelector::notebookCreated,
  217. m_dirTree, [this](const QString &p_name, bool p_import) {
  218. Q_UNUSED(p_name);
  219. if (!p_import) {
  220. m_dirTree->newRootDirectory();
  221. }
  222. });
  223. connect(m_fileList, &VFileList::fileClicked,
  224. m_editArea, &VEditArea::openFile);
  225. connect(m_fileList, &VFileList::fileCreated,
  226. m_editArea, &VEditArea::openFile);
  227. connect(m_fileList, &VFileList::fileUpdated,
  228. m_editArea, &VEditArea::handleFileUpdated);
  229. connect(m_editArea, &VEditArea::tabStatusUpdated,
  230. this, &VMainWindow::handleAreaTabStatusUpdated);
  231. connect(m_editArea, &VEditArea::statusMessage,
  232. this, &VMainWindow::showStatusMessage);
  233. connect(m_editArea, &VEditArea::vimStatusUpdated,
  234. this, &VMainWindow::handleVimStatusUpdated);
  235. connect(m_findReplaceDialog, &VFindReplaceDialog::findTextChanged,
  236. this, &VMainWindow::handleFindDialogTextChanged);
  237. setCentralWidget(m_mainSplitter);
  238. initVimCmd();
  239. m_vimIndicator = new VVimIndicator(this);
  240. m_vimIndicator->hide();
  241. m_tabIndicator = new VTabIndicator(this);
  242. m_tabIndicator->hide();
  243. // Create and show the status bar
  244. statusBar()->addPermanentWidget(m_vimCmd);
  245. statusBar()->addPermanentWidget(m_vimIndicator);
  246. statusBar()->addPermanentWidget(m_tabIndicator);
  247. initTrayIcon();
  248. }
  249. void VMainWindow::setupNaviBox()
  250. {
  251. m_naviBox = new VToolBox();
  252. setupNotebookPanel();
  253. m_naviBox->addItem(m_nbSplitter,
  254. ":/resources/icons/notebook.svg",
  255. tr("Notebooks"),
  256. m_dirTree);
  257. m_historyList = new VHistoryList();
  258. m_naviBox->addItem(m_historyList,
  259. ":/resources/icons/history.svg",
  260. tr("History"));
  261. m_explorer = new VExplorer();
  262. m_naviBox->addItem(m_explorer,
  263. ":/resources/icons/explorer.svg",
  264. tr("Explorer"));
  265. m_tagExplorer = new VTagExplorer();
  266. m_naviBox->addItem(m_tagExplorer,
  267. ":/resources/icons/tag_explorer.svg",
  268. tr("Tags"));
  269. connect(m_notebookSelector, &VNotebookSelector::curNotebookChanged,
  270. m_tagExplorer, &VTagExplorer::setNotebook);
  271. }
  272. void VMainWindow::setupNotebookPanel()
  273. {
  274. m_notebookSelector = new VNotebookSelector();
  275. m_notebookSelector->setObjectName("NotebookSelector");
  276. m_notebookSelector->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLengthWithIcon);
  277. // Folders.
  278. QLabel *directoryLabel = new QLabel(tr("Folders"));
  279. directoryLabel->setProperty("TitleLabel", true);
  280. m_dirTree = new VDirectoryTree;
  281. QVBoxLayout *naviLayout = new QVBoxLayout;
  282. naviLayout->addWidget(m_notebookSelector);
  283. naviLayout->addWidget(directoryLabel);
  284. naviLayout->addWidget(m_dirTree);
  285. naviLayout->setContentsMargins(0, 0, 0, 0);
  286. naviLayout->setSpacing(0);
  287. QWidget *naviWidget = new QWidget();
  288. naviWidget->setLayout(naviLayout);
  289. // Notes.
  290. m_fileList = new VFileList();
  291. m_fileList->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Expanding);
  292. m_nbSplitter = new QSplitter();
  293. m_nbSplitter->setOrientation(Qt::Vertical);
  294. m_nbSplitter->setObjectName("NotebookSplitter");
  295. m_nbSplitter->addWidget(naviWidget);
  296. m_nbSplitter->addWidget(m_fileList);
  297. m_nbSplitter->setStretchFactor(0, 1);
  298. m_nbSplitter->setStretchFactor(1, 2);
  299. connect(m_notebookSelector, &VNotebookSelector::curNotebookChanged,
  300. this, [this](VNotebook *p_notebook) {
  301. m_dirTree->setNotebook(p_notebook);
  302. m_dirTree->setFocus();
  303. });
  304. connect(m_notebookSelector, &VNotebookSelector::curNotebookChanged,
  305. this, &VMainWindow::handleCurrentNotebookChanged);
  306. connect(m_dirTree, &VDirectoryTree::currentDirectoryChanged,
  307. this, &VMainWindow::handleCurrentDirectoryChanged);
  308. connect(m_dirTree, &VDirectoryTree::currentDirectoryChanged,
  309. m_fileList, &VFileList::setDirectory);
  310. }
  311. void VMainWindow::initToolBar()
  312. {
  313. const int tbIconSize = g_config->getToolBarIconSize() * VUtils::calculateScaleFactor();
  314. QSize iconSize(tbIconSize, tbIconSize);
  315. m_toolBars.append(initFileToolBar(iconSize));
  316. m_toolBars.append(initViewToolBar(iconSize));
  317. m_toolBars.append(initEditToolBar(iconSize));
  318. m_toolBars.append(initNoteToolBar(iconSize));
  319. setToolBarVisible(g_config->getToolBarChecked());
  320. }
  321. QToolBar *VMainWindow::initViewToolBar(QSize p_iconSize)
  322. {
  323. m_viewToolBar = addToolBar(tr("View"));
  324. m_viewToolBar->setObjectName("ViewToolBar");
  325. m_viewToolBar->setMovable(false);
  326. if (p_iconSize.isValid()) {
  327. m_viewToolBar->setIconSize(p_iconSize);
  328. }
  329. QAction *fullScreenAct = new QAction(VIconUtils::toolButtonIcon(":/resources/icons/fullscreen.svg"),
  330. tr("Full Screen"),
  331. this);
  332. QString keySeq = g_config->getShortcutKeySequence("FullScreen");
  333. QKeySequence seq(keySeq);
  334. if (!seq.isEmpty()) {
  335. fullScreenAct->setText(tr("Full Screen\t%1").arg(VUtils::getShortcutText(keySeq)));
  336. fullScreenAct->setShortcut(seq);
  337. }
  338. fullScreenAct->setStatusTip(tr("Toggle full screen"));
  339. connect(fullScreenAct, &QAction::triggered,
  340. this, [this]() {
  341. if (windowState() & Qt::WindowFullScreen) {
  342. if (m_windowOldState & Qt::WindowMaximized) {
  343. showMaximized();
  344. } else {
  345. showNormal();
  346. }
  347. } else {
  348. showFullScreen();
  349. }
  350. });
  351. QAction *stayOnTopAct = new QAction(VIconUtils::toolButtonIcon(":/resources/icons/stay_on_top.svg"),
  352. tr("Stay On Top"),
  353. this);
  354. stayOnTopAct->setStatusTip(tr("Toggle stay-on-top"));
  355. stayOnTopAct->setCheckable(true);
  356. connect(stayOnTopAct, &QAction::triggered,
  357. this, &VMainWindow::stayOnTop);
  358. QAction *menuBarAct = new QAction(VIconUtils::toolButtonIcon(":/resources/icons/menubar.svg"),
  359. tr("Menu Bar"),
  360. this);
  361. menuBarAct->setStatusTip(tr("Toggle menu bar"));
  362. menuBarAct->setCheckable(true);
  363. menuBarAct->setChecked(g_config->getMenuBarChecked());
  364. connect(menuBarAct, &QAction::triggered,
  365. this, [this](bool p_checked) {
  366. setMenuBarVisible(p_checked);
  367. g_config->setMenuBarChecked(p_checked);
  368. });
  369. QMenu *viewMenu = new QMenu(this);
  370. viewMenu->setToolTipsVisible(true);
  371. viewMenu->addAction(fullScreenAct);
  372. viewMenu->addAction(stayOnTopAct);
  373. viewMenu->addAction(menuBarAct);
  374. expandViewAct = new QAction(VIconUtils::toolButtonIcon(":/resources/icons/expand.svg"),
  375. tr("Expand"),
  376. this);
  377. VUtils::fixTextWithCaptainShortcut(expandViewAct, "ExpandMode");
  378. expandViewAct->setStatusTip(tr("Expand the edit area"));
  379. expandViewAct->setCheckable(true);
  380. expandViewAct->setMenu(viewMenu);
  381. connect(expandViewAct, &QAction::triggered,
  382. this, [this](bool p_checked) {
  383. changePanelView(p_checked ? PanelViewState::ExpandMode
  384. : PanelViewState::VerticalMode);
  385. });
  386. m_viewToolBar->addAction(expandViewAct);
  387. return m_viewToolBar;
  388. }
  389. // Enable/disable all actions of @p_widget.
  390. static void setActionsEnabled(QWidget *p_widget, bool p_enabled)
  391. {
  392. Q_ASSERT(p_widget);
  393. QList<QAction *> actions = p_widget->actions();
  394. for (auto const & act : actions) {
  395. act->setEnabled(p_enabled);
  396. }
  397. }
  398. QToolBar *VMainWindow::initEditToolBar(QSize p_iconSize)
  399. {
  400. m_editToolBar = addToolBar(tr("Edit Toolbar"));
  401. m_editToolBar->setObjectName("EditToolBar");
  402. m_editToolBar->setMovable(false);
  403. if (p_iconSize.isValid()) {
  404. m_editToolBar->setIconSize(p_iconSize);
  405. }
  406. m_editToolBar->addSeparator();
  407. m_headingSequenceAct = new QAction(VIconUtils::toolButtonIcon(":/resources/icons/heading_sequence.svg"),
  408. tr("Heading Sequence"),
  409. this);
  410. m_headingSequenceAct->setStatusTip(tr("Enable heading sequence in current note in edit mode"));
  411. m_headingSequenceAct->setCheckable(true);
  412. connect(m_headingSequenceAct, &QAction::triggered,
  413. this, [this](bool p_checked){
  414. if (isHeadingSequenceApplicable()) {
  415. VMdTab *tab = dynamic_cast<VMdTab *>(m_curTab.data());
  416. Q_ASSERT(tab);
  417. tab->enableHeadingSequence(p_checked);
  418. }
  419. });
  420. m_editToolBar->addAction(m_headingSequenceAct);
  421. initHeadingButton(m_editToolBar);
  422. QAction *boldAct = new QAction(VIconUtils::toolButtonIcon(":/resources/icons/bold.svg"),
  423. tr("Bold\t%1").arg(VUtils::getShortcutText("Ctrl+B")),
  424. this);
  425. boldAct->setStatusTip(tr("Insert bold text or change selected text to bold"));
  426. connect(boldAct, &QAction::triggered,
  427. this, [this](){
  428. if (m_curTab) {
  429. m_curTab->decorateText(TextDecoration::Bold);
  430. }
  431. });
  432. m_editToolBar->addAction(boldAct);
  433. QAction *italicAct = new QAction(VIconUtils::toolButtonIcon(":/resources/icons/italic.svg"),
  434. tr("Italic\t%1").arg(VUtils::getShortcutText("Ctrl+I")),
  435. this);
  436. italicAct->setStatusTip(tr("Insert italic text or change selected text to italic"));
  437. connect(italicAct, &QAction::triggered,
  438. this, [this](){
  439. if (m_curTab) {
  440. m_curTab->decorateText(TextDecoration::Italic);
  441. }
  442. });
  443. m_editToolBar->addAction(italicAct);
  444. QAction *strikethroughAct = new QAction(VIconUtils::toolButtonIcon(":/resources/icons/strikethrough.svg"),
  445. tr("Strikethrough\t%1").arg(VUtils::getShortcutText("Ctrl+D")),
  446. this);
  447. strikethroughAct->setStatusTip(tr("Insert strikethrough text or change selected text to strikethroughed"));
  448. connect(strikethroughAct, &QAction::triggered,
  449. this, [this](){
  450. if (m_curTab) {
  451. m_curTab->decorateText(TextDecoration::Strikethrough);
  452. }
  453. });
  454. m_editToolBar->addAction(strikethroughAct);
  455. QAction *inlineCodeAct = new QAction(VIconUtils::toolButtonIcon(":/resources/icons/inline_code.svg"),
  456. tr("Inline Code\t%1").arg(VUtils::getShortcutText("Ctrl+;")),
  457. this);
  458. inlineCodeAct->setStatusTip(tr("Insert inline-code text or change selected text to inline-coded"));
  459. connect(inlineCodeAct, &QAction::triggered,
  460. this, [this](){
  461. if (m_curTab) {
  462. m_curTab->decorateText(TextDecoration::InlineCode);
  463. }
  464. });
  465. m_editToolBar->addAction(inlineCodeAct);
  466. QAction *codeBlockAct = new QAction(VIconUtils::toolButtonIcon(":/resources/icons/code_block.svg"),
  467. tr("Code Block\t%1").arg(VUtils::getShortcutText("Ctrl+M")),
  468. this);
  469. codeBlockAct->setStatusTip(tr("Insert fenced code block text or wrap selected text into a fenced code block"));
  470. connect(codeBlockAct, &QAction::triggered,
  471. this, [this](){
  472. if (m_curTab) {
  473. m_curTab->decorateText(TextDecoration::CodeBlock);
  474. }
  475. });
  476. m_editToolBar->addAction(codeBlockAct);
  477. // Insert link.
  478. QAction *insetLinkAct = new QAction(VIconUtils::toolButtonIcon(":/resources/icons/link.svg"),
  479. tr("Insert Link\t%1").arg(VUtils::getShortcutText("Ctrl+L")),
  480. this);
  481. insetLinkAct->setStatusTip(tr("Insert a link"));
  482. connect(insetLinkAct, &QAction::triggered,
  483. this, [this]() {
  484. if (m_curTab) {
  485. m_curTab->insertLink();
  486. }
  487. });
  488. m_editToolBar->addAction(insetLinkAct);
  489. // Insert image.
  490. QAction *insertImageAct = new QAction(VIconUtils::toolButtonIcon(":/resources/icons/insert_image.svg"),
  491. tr("Insert Image\t%1").arg(VUtils::getShortcutText("Ctrl+'")),
  492. this);
  493. insertImageAct->setStatusTip(tr("Insert an image from file or URL"));
  494. connect(insertImageAct, &QAction::triggered,
  495. this, [this]() {
  496. if (m_curTab) {
  497. m_curTab->insertImage();
  498. }
  499. });
  500. m_editToolBar->addAction(insertImageAct);
  501. setActionsEnabled(m_editToolBar, false);
  502. return m_editToolBar;
  503. }
  504. QToolBar *VMainWindow::initNoteToolBar(QSize p_iconSize)
  505. {
  506. m_noteToolBar = addToolBar(tr("Note Toolbar"));
  507. m_noteToolBar->setObjectName("NoteToolBar");
  508. m_noteToolBar->setMovable(false);
  509. if (p_iconSize.isValid()) {
  510. m_noteToolBar->setIconSize(p_iconSize);
  511. }
  512. m_noteToolBar->addSeparator();
  513. // Attachment.
  514. m_attachmentList = new VAttachmentList(this);
  515. m_attachmentBtn = new VButtonWithWidget(VIconUtils::toolButtonIcon(":/resources/icons/attachment.svg"),
  516. "",
  517. m_attachmentList,
  518. this);
  519. m_attachmentBtn->setBubbleColor(g_palette->color("bubble_fg"),
  520. g_palette->color("bubble_bg"));
  521. m_attachmentBtn->setToolTip(tr("Attachments (drag files here to add attachments)"));
  522. m_attachmentBtn->setProperty("CornerBtn", true);
  523. m_attachmentBtn->setFocusPolicy(Qt::NoFocus);
  524. m_attachmentBtn->setEnabled(false);
  525. QAction *flashPageAct = new QAction(VIconUtils::toolButtonIcon(":/resources/icons/flash_page.svg"),
  526. tr("Flash Page"),
  527. this);
  528. flashPageAct->setStatusTip(tr("Open the Flash Page to edit"));
  529. QString keySeq = g_config->getShortcutKeySequence("FlashPage");
  530. QKeySequence seq(keySeq);
  531. if (!seq.isEmpty()) {
  532. flashPageAct->setText(tr("Flash Page\t%1").arg(VUtils::getShortcutText(keySeq)));
  533. flashPageAct->setShortcut(seq);
  534. }
  535. connect(flashPageAct, &QAction::triggered,
  536. this, &VMainWindow::openFlashPage);
  537. QAction *quickAccessAct = new QAction(VIconUtils::toolButtonIcon(":/resources/icons/quick_access.svg"),
  538. tr("Quick Access"),
  539. this);
  540. quickAccessAct->setStatusTip(tr("Open quick access note"));
  541. keySeq = g_config->getShortcutKeySequence("QuickAccess");
  542. seq = QKeySequence(keySeq);
  543. if (!seq.isEmpty()) {
  544. quickAccessAct->setText(tr("Quick Access\t%1").arg(VUtils::getShortcutText(keySeq)));
  545. quickAccessAct->setShortcut(seq);
  546. }
  547. connect(quickAccessAct, &QAction::triggered,
  548. this, &VMainWindow::openQuickAccess);
  549. QAction *universalEntryAct = new QAction(VIconUtils::toolButtonIcon(":/resources/icons/universal_entry_tb.svg"),
  550. tr("Universal Entry"),
  551. this);
  552. universalEntryAct->setStatusTip(tr("Activate Universal Entry"));
  553. keySeq = g_config->getShortcutKeySequence("UniversalEntry");
  554. seq = QKeySequence(keySeq);
  555. if (!seq.isEmpty()) {
  556. universalEntryAct->setText(tr("Universal Entry\t%1").arg(VUtils::getShortcutText(keySeq)));
  557. universalEntryAct->setShortcut(seq);
  558. }
  559. connect(universalEntryAct, &QAction::triggered,
  560. this, &VMainWindow::activateUniversalEntry);
  561. m_noteToolBar->addWidget(m_attachmentBtn);
  562. m_noteToolBar->addAction(flashPageAct);
  563. m_noteToolBar->addAction(quickAccessAct);
  564. m_noteToolBar->addAction(universalEntryAct);
  565. return m_noteToolBar;
  566. }
  567. QToolBar *VMainWindow::initFileToolBar(QSize p_iconSize)
  568. {
  569. m_fileToolBar = addToolBar(tr("Note"));
  570. m_fileToolBar->setObjectName("FileToolBar");
  571. m_fileToolBar->setMovable(false);
  572. if (p_iconSize.isValid()) {
  573. m_fileToolBar->setIconSize(p_iconSize);
  574. }
  575. m_avatarBtn = new QPushButton("VNote", this);
  576. m_avatarBtn->setProperty("AvatarBtn", true);
  577. m_avatarBtn->setFocusPolicy(Qt::NoFocus);
  578. m_avatarBtn->setToolTip(tr("Log In (Not Implemented Yet)"));
  579. newRootDirAct = new QAction(VIconUtils::toolButtonIcon(":/resources/icons/create_rootdir_tb.svg"),
  580. tr("New Root Folder"),
  581. this);
  582. newRootDirAct->setStatusTip(tr("Create a root folder in current notebook"));
  583. connect(newRootDirAct, &QAction::triggered,
  584. m_dirTree, &VDirectoryTree::newRootDirectory);
  585. newNoteAct = new QAction(VIconUtils::toolButtonIcon(":/resources/icons/create_note_tb.svg"),
  586. tr("New Note"), this);
  587. newNoteAct->setStatusTip(tr("Create a note in current folder"));
  588. QString keySeq = g_config->getShortcutKeySequence("NewNote");
  589. QKeySequence seq(keySeq);
  590. if (!seq.isEmpty()) {
  591. newNoteAct->setText(tr("New Note\t%1").arg(VUtils::getShortcutText(keySeq)));
  592. newNoteAct->setShortcut(seq);
  593. }
  594. connect(newNoteAct, &QAction::triggered,
  595. m_fileList, &VFileList::newFile);
  596. noteInfoAct = new QAction(VIconUtils::toolButtonIcon(":/resources/icons/note_info_tb.svg"),
  597. tr("Note Info"), this);
  598. noteInfoAct->setStatusTip(tr("View and edit current note's information"));
  599. connect(noteInfoAct, &QAction::triggered,
  600. this, &VMainWindow::curEditFileInfo);
  601. deleteNoteAct = new QAction(VIconUtils::toolButtonDangerIcon(":/resources/icons/delete_note_tb.svg"),
  602. tr("Delete Note"), this);
  603. deleteNoteAct->setStatusTip(tr("Delete current note"));
  604. connect(deleteNoteAct, &QAction::triggered,
  605. this, &VMainWindow::deleteCurNote);
  606. m_editReadAct = new QAction(this);
  607. connect(m_editReadAct, &QAction::triggered,
  608. this, &VMainWindow::toggleEditReadMode);
  609. m_discardExitAct = new QAction(VIconUtils::menuIcon(":/resources/icons/discard_exit.svg"),
  610. tr("Discard Changes And Read"),
  611. this);
  612. VUtils::fixTextWithCaptainShortcut(m_discardExitAct, "DiscardAndRead");
  613. m_discardExitAct->setStatusTip(tr("Discard changes and exit edit mode"));
  614. connect(m_discardExitAct, &QAction::triggered,
  615. this, [this]() {
  616. m_editArea->readFile(true);
  617. });
  618. updateEditReadAct(NULL);
  619. saveNoteAct = new QAction(VIconUtils::toolButtonIcon(":/resources/icons/save_note.svg"),
  620. tr("Save"), this);
  621. saveNoteAct->setStatusTip(tr("Save changes to current note"));
  622. keySeq = g_config->getShortcutKeySequence("SaveNote");
  623. seq = QKeySequence(keySeq);
  624. if (!seq.isEmpty()) {
  625. saveNoteAct->setText(tr("Save\t%1").arg(VUtils::getShortcutText(keySeq)));
  626. saveNoteAct->setShortcut(seq);
  627. }
  628. connect(saveNoteAct, &QAction::triggered,
  629. m_editArea, &VEditArea::saveFile);
  630. newRootDirAct->setEnabled(false);
  631. newNoteAct->setEnabled(false);
  632. noteInfoAct->setEnabled(false);
  633. deleteNoteAct->setEnabled(false);
  634. m_editReadAct->setEnabled(false);
  635. m_discardExitAct->setEnabled(false);
  636. saveNoteAct->setEnabled(false);
  637. m_fileToolBar->addWidget(m_avatarBtn);
  638. m_fileToolBar->addAction(newRootDirAct);
  639. m_fileToolBar->addAction(newNoteAct);
  640. m_fileToolBar->addAction(deleteNoteAct);
  641. m_fileToolBar->addAction(noteInfoAct);
  642. m_fileToolBar->addAction(m_editReadAct);
  643. m_fileToolBar->addAction(m_discardExitAct);
  644. m_fileToolBar->addAction(saveNoteAct);
  645. return m_fileToolBar;
  646. }
  647. void VMainWindow::initMenuBar()
  648. {
  649. initFileMenu();
  650. initEditMenu();
  651. initViewMenu();
  652. initMarkdownMenu();
  653. initHelpMenu();
  654. setMenuBarVisible(g_config->getMenuBarChecked());
  655. }
  656. void VMainWindow::initHelpMenu()
  657. {
  658. QMenu *helpMenu = menuBar()->addMenu(tr("&Help"));
  659. helpMenu->setToolTipsVisible(true);
  660. #if defined(QT_NO_DEBUG)
  661. QAction *logAct = new QAction(tr("View &Log"), this);
  662. logAct->setToolTip(tr("View VNote's debug log (%1)").arg(g_config->getLogFilePath()));
  663. connect(logAct, &QAction::triggered,
  664. this, [](){
  665. QUrl url = QUrl::fromLocalFile(g_config->getLogFilePath());
  666. QDesktopServices::openUrl(url);
  667. });
  668. #endif
  669. QAction *shortcutAct = new QAction(tr("&Shortcuts Help"), this);
  670. shortcutAct->setToolTip(tr("View information about shortcut keys"));
  671. VUtils::fixTextWithCaptainShortcut(shortcutAct, "ShortcutsHelp");
  672. connect(shortcutAct, &QAction::triggered,
  673. this, &VMainWindow::shortcutsHelp);
  674. QAction *mdGuideAct = new QAction(tr("&Markdown Guide"), this);
  675. mdGuideAct->setToolTip(tr("A quick guide of Markdown syntax"));
  676. connect(mdGuideAct, &QAction::triggered,
  677. this, [this](){
  678. QString docFile = VUtils::getDocFile(VNote::c_markdownGuideDocFile);
  679. VFile *file = vnote->getFile(docFile, true);
  680. m_editArea->openFile(file, OpenFileMode::Read);
  681. });
  682. QAction *docAct = new QAction(tr("&Documentation"), this);
  683. docAct->setToolTip(tr("View VNote's documentation"));
  684. connect(docAct, &QAction::triggered,
  685. this, []() {
  686. QString url("http://vnote.readthedocs.io");
  687. QDesktopServices::openUrl(url);
  688. });
  689. QAction *donateAct = new QAction(tr("Do&nate"), this);
  690. donateAct->setToolTip(tr("Donate to VNote or view the donate list"));
  691. connect(donateAct, &QAction::triggered,
  692. this, []() {
  693. QString url("https://github.com/tamlok/vnote#donate");
  694. QDesktopServices::openUrl(url);
  695. });
  696. QAction *updateAct = new QAction(tr("Check For &Updates"), this);
  697. updateAct->setToolTip(tr("Check for updates of VNote"));
  698. connect(updateAct, &QAction::triggered,
  699. this, [this](){
  700. VUpdater updater(this);
  701. updater.exec();
  702. });
  703. QAction *starAct = new QAction(tr("Star VNote on &Github"), this);
  704. starAct->setToolTip(tr("Give a star to VNote on Github project"));
  705. connect(starAct, &QAction::triggered,
  706. this, []() {
  707. QString url("https://github.com/tamlok/vnote");
  708. QDesktopServices::openUrl(url);
  709. });
  710. QAction *feedbackAct = new QAction(tr("&Feedback"), this);
  711. feedbackAct->setToolTip(tr("Open an issue on Github"));
  712. connect(feedbackAct, &QAction::triggered,
  713. this, []() {
  714. QString url("https://github.com/tamlok/vnote/issues");
  715. QDesktopServices::openUrl(url);
  716. });
  717. QAction *aboutAct = new QAction(tr("&About VNote"), this);
  718. aboutAct->setToolTip(tr("View information about VNote"));
  719. aboutAct->setMenuRole(QAction::AboutRole);
  720. connect(aboutAct, &QAction::triggered,
  721. this, &VMainWindow::aboutMessage);
  722. QAction *aboutQtAct = new QAction(tr("About &Qt"), this);
  723. aboutQtAct->setToolTip(tr("View information about Qt"));
  724. aboutQtAct->setMenuRole(QAction::AboutQtRole);
  725. connect(aboutQtAct, &QAction::triggered,
  726. qApp, &QApplication::aboutQt);
  727. helpMenu->addAction(shortcutAct);
  728. helpMenu->addAction(mdGuideAct);
  729. helpMenu->addAction(docAct);
  730. helpMenu->addAction(donateAct);
  731. helpMenu->addAction(updateAct);
  732. helpMenu->addAction(starAct);
  733. helpMenu->addAction(feedbackAct);
  734. #if defined(QT_NO_DEBUG)
  735. helpMenu->addAction(logAct);
  736. #endif
  737. helpMenu->addAction(aboutQtAct);
  738. helpMenu->addAction(aboutAct);
  739. }
  740. void VMainWindow::initMarkdownMenu()
  741. {
  742. QMenu *markdownMenu = menuBar()->addMenu(tr("&Markdown"));
  743. markdownMenu->setToolTipsVisible(true);
  744. initConverterMenu(markdownMenu);
  745. initMarkdownitOptionMenu(markdownMenu);
  746. markdownMenu->addSeparator();
  747. initRenderStyleMenu(markdownMenu);
  748. initRenderBackgroundMenu(markdownMenu);
  749. initCodeBlockStyleMenu(markdownMenu);
  750. QAction *constrainImageAct = new QAction(tr("Constrain The Width Of Images"), this);
  751. constrainImageAct->setToolTip(tr("Constrain the width of images to the window in read mode (re-open current tabs to make it work)"));
  752. constrainImageAct->setCheckable(true);
  753. connect(constrainImageAct, &QAction::triggered,
  754. this, &VMainWindow::enableImageConstraint);
  755. markdownMenu->addAction(constrainImageAct);
  756. constrainImageAct->setChecked(g_config->getEnableImageConstraint());
  757. QAction *imageCaptionAct = new QAction(tr("Enable Image Caption"), this);
  758. imageCaptionAct->setToolTip(tr("Center the images and display the alt text as caption (re-open current tabs to make it work)"));
  759. imageCaptionAct->setCheckable(true);
  760. connect(imageCaptionAct, &QAction::triggered,
  761. this, &VMainWindow::enableImageCaption);
  762. markdownMenu->addAction(imageCaptionAct);
  763. imageCaptionAct->setChecked(g_config->getEnableImageCaption());
  764. markdownMenu->addSeparator();
  765. QAction *mermaidAct = new QAction(tr("&Mermaid Diagram"), this);
  766. mermaidAct->setToolTip(tr("Enable Mermaid for graph and diagram (re-open current tabs to make it work)"));
  767. mermaidAct->setCheckable(true);
  768. connect(mermaidAct, &QAction::triggered,
  769. this, &VMainWindow::enableMermaid);
  770. markdownMenu->addAction(mermaidAct);
  771. mermaidAct->setChecked(g_config->getEnableMermaid());
  772. QAction *flowchartAct = new QAction(tr("&Flowchart.js"), this);
  773. flowchartAct->setToolTip(tr("Enable Flowchart.js for flowchart diagram (re-open current tabs to make it work)"));
  774. flowchartAct->setCheckable(true);
  775. connect(flowchartAct, &QAction::triggered,
  776. this, [this](bool p_enabled){
  777. g_config->setEnableFlowchart(p_enabled);
  778. VUtils::promptForReopen(this);
  779. });
  780. markdownMenu->addAction(flowchartAct);
  781. flowchartAct->setChecked(g_config->getEnableFlowchart());
  782. QAction *mathjaxAct = new QAction(tr("Math&Jax"), this);
  783. mathjaxAct->setToolTip(tr("Enable MathJax for math support in Markdown (re-open current tabs to make it work)"));
  784. mathjaxAct->setCheckable(true);
  785. connect(mathjaxAct, &QAction::triggered,
  786. this, &VMainWindow::enableMathjax);
  787. markdownMenu->addAction(mathjaxAct);
  788. mathjaxAct->setChecked(g_config->getEnableMathjax());
  789. markdownMenu->addSeparator();
  790. QAction *codeBlockAct = new QAction(tr("Highlight Code Blocks In Edit Mode"), this);
  791. codeBlockAct->setToolTip(tr("Enable syntax highlight within code blocks in edit mode"));
  792. codeBlockAct->setCheckable(true);
  793. connect(codeBlockAct, &QAction::triggered,
  794. this, &VMainWindow::enableCodeBlockHighlight);
  795. markdownMenu->addAction(codeBlockAct);
  796. codeBlockAct->setChecked(g_config->getEnableCodeBlockHighlight());
  797. QAction *lineNumberAct = new QAction(tr("Display Line Number In Code Blocks"), this);
  798. lineNumberAct->setToolTip(tr("Enable line number in code blocks in read mode"));
  799. lineNumberAct->setCheckable(true);
  800. connect(lineNumberAct, &QAction::triggered,
  801. this, [](bool p_checked){
  802. g_config->setEnableCodeBlockLineNumber(p_checked);
  803. });
  804. markdownMenu->addAction(lineNumberAct);
  805. lineNumberAct->setChecked(g_config->getEnableCodeBlockLineNumber());
  806. QAction *previewImageAct = new QAction(tr("In-Place Preview"), this);
  807. previewImageAct->setToolTip(tr("Enable in-place preview (images, diagrams, and formulas) in edit mode (re-open current tabs to make it work)"));
  808. previewImageAct->setCheckable(true);
  809. connect(previewImageAct, &QAction::triggered,
  810. this, &VMainWindow::enableImagePreview);
  811. markdownMenu->addAction(previewImageAct);
  812. previewImageAct->setChecked(g_config->getEnablePreviewImages());
  813. QAction *previewWidthAct = new QAction(tr("Constrain The Width Of In-Place Preview"), this);
  814. previewWidthAct->setToolTip(tr("Constrain the width of in-place preview to the edit window in edit mode"));
  815. previewWidthAct->setCheckable(true);
  816. connect(previewWidthAct, &QAction::triggered,
  817. this, &VMainWindow::enableImagePreviewConstraint);
  818. markdownMenu->addAction(previewWidthAct);
  819. previewWidthAct->setChecked(g_config->getEnablePreviewImageConstraint());
  820. }
  821. void VMainWindow::initViewMenu()
  822. {
  823. m_viewMenu = menuBar()->addMenu(tr("&View"));
  824. m_viewMenu->setToolTipsVisible(true);
  825. m_toolBarAct = new QAction(tr("Tool Bar"), this);
  826. m_toolBarAct->setToolTip(tr("Toogle the tool bar"));
  827. VUtils::fixTextWithCaptainShortcut(m_toolBarAct, "ToolBar");
  828. m_toolBarAct->setCheckable(true);
  829. m_toolBarAct->setChecked(g_config->getToolBarChecked());
  830. connect(m_toolBarAct, &QAction::triggered,
  831. this, [this] (bool p_checked) {
  832. g_config->setToolBarChecked(p_checked);
  833. setToolBarVisible(p_checked);
  834. });
  835. m_viewMenu->addAction(m_toolBarAct);
  836. }
  837. void VMainWindow::initFileMenu()
  838. {
  839. QMenu *fileMenu = menuBar()->addMenu(tr("&File"));
  840. fileMenu->setToolTipsVisible(true);
  841. // Open external files.
  842. QAction *openAct = new QAction(tr("&Open"), this);
  843. openAct->setToolTip(tr("Open external file to edit"));
  844. connect(openAct, &QAction::triggered,
  845. this, [this](){
  846. static QString lastPath = QDir::homePath();
  847. QStringList files = QFileDialog::getOpenFileNames(this,
  848. tr("Select External Files To Open"),
  849. lastPath);
  850. if (files.isEmpty()) {
  851. return;
  852. }
  853. // Update lastPath
  854. lastPath = QFileInfo(files[0]).path();
  855. openFiles(VUtils::filterFilePathsToOpen(files),
  856. false,
  857. g_config->getNoteOpenMode(),
  858. false,
  859. false);
  860. });
  861. fileMenu->addAction(openAct);
  862. // Import notes from files.
  863. m_importNoteAct = newAction(VIconUtils::menuIcon(":/resources/icons/import_note.svg"),
  864. tr("&New Notes From Files"), this);
  865. m_importNoteAct->setToolTip(tr("Create notes from external files in current folder "
  866. "(will copy files if they do not locate in current folder)"));
  867. connect(m_importNoteAct, &QAction::triggered,
  868. this, &VMainWindow::importNoteFromFile);
  869. m_importNoteAct->setEnabled(false);
  870. fileMenu->addAction(m_importNoteAct);
  871. fileMenu->addSeparator();
  872. // Export as PDF.
  873. m_exportAct = new QAction(tr("E&xport"), this);
  874. m_exportAct->setToolTip(tr("Export notes"));
  875. VUtils::fixTextWithCaptainShortcut(m_exportAct, "Export");
  876. connect(m_exportAct, &QAction::triggered,
  877. this, &VMainWindow::handleExportAct);
  878. fileMenu->addAction(m_exportAct);
  879. // Print.
  880. m_printAct = new QAction(VIconUtils::menuIcon(":/resources/icons/print.svg"),
  881. tr("&Print"), this);
  882. m_printAct->setToolTip(tr("Print current note"));
  883. connect(m_printAct, &QAction::triggered,
  884. this, &VMainWindow::printNote);
  885. m_printAct->setEnabled(false);
  886. fileMenu->addAction(m_printAct);
  887. fileMenu->addSeparator();
  888. // Themes.
  889. initThemeMenu(fileMenu);
  890. // Settings.
  891. QAction *settingsAct = newAction(VIconUtils::menuIcon(":/resources/icons/settings.svg"),
  892. tr("&Settings"), this);
  893. settingsAct->setToolTip(tr("View and change settings for VNote"));
  894. settingsAct->setMenuRole(QAction::PreferencesRole);
  895. connect(settingsAct, &QAction::triggered,
  896. this, &VMainWindow::viewSettings);
  897. fileMenu->addAction(settingsAct);
  898. QAction *openConfigAct = new QAction(tr("Open Configuration Folder"), this);
  899. openConfigAct->setToolTip(tr("Open configuration folder of VNote"));
  900. connect(openConfigAct, &QAction::triggered,
  901. this, [](){
  902. QUrl url = QUrl::fromLocalFile(g_config->getConfigFolder());
  903. QDesktopServices::openUrl(url);
  904. });
  905. fileMenu->addAction(openConfigAct);
  906. QAction *customShortcutAct = new QAction(tr("Customize Shortcuts"), this);
  907. customShortcutAct->setToolTip(tr("Customize some standard shortcuts"));
  908. connect(customShortcutAct, &QAction::triggered,
  909. this, &VMainWindow::customShortcut);
  910. fileMenu->addAction(customShortcutAct);
  911. fileMenu->addSeparator();
  912. // Restart.
  913. QAction *restartAct = new QAction(tr("Restart"), this);
  914. connect(restartAct, &QAction::triggered,
  915. this, &VMainWindow::restartVNote);
  916. fileMenu->addAction(restartAct);
  917. // Exit.
  918. QAction *exitAct = new QAction(tr("&Quit"), this);
  919. exitAct->setToolTip(tr("Quit VNote"));
  920. exitAct->setShortcut(QKeySequence("Ctrl+Q"));
  921. exitAct->setMenuRole(QAction::QuitRole);
  922. connect(exitAct, &QAction::triggered,
  923. this, &VMainWindow::quitApp);
  924. fileMenu->addAction(exitAct);
  925. }
  926. void VMainWindow::quitApp()
  927. {
  928. m_requestQuit = true;
  929. close();
  930. }
  931. void VMainWindow::initEditMenu()
  932. {
  933. QMenu *editMenu = menuBar()->addMenu(tr("&Edit"));
  934. editMenu->setToolTipsVisible(true);
  935. // Find/Replace.
  936. m_findReplaceAct = newAction(VIconUtils::menuIcon(":/resources/icons/find_replace.svg"),
  937. tr("Find/Replace"), this);
  938. m_findReplaceAct->setToolTip(tr("Open Find/Replace dialog to search in current note"));
  939. QString keySeq = g_config->getShortcutKeySequence("Find");
  940. qDebug() << "set Find shortcut to" << keySeq;
  941. m_findReplaceAct->setShortcut(QKeySequence(keySeq));
  942. connect(m_findReplaceAct, &QAction::triggered,
  943. this, &VMainWindow::openFindDialog);
  944. QAction *advFindAct = new QAction(tr("Advanced Find"), this);
  945. advFindAct->setToolTip(tr("Advanced find within VNote"));
  946. keySeq = g_config->getShortcutKeySequence("AdvancedFind");
  947. qDebug() << "set AdvancedFind shortcut to" << keySeq;
  948. advFindAct->setShortcut(QKeySequence(keySeq));
  949. connect(advFindAct, &QAction::triggered,
  950. this, [this]() {
  951. m_searchDock->setVisible(true);
  952. m_searcher->focusToSearch();
  953. });
  954. m_findNextAct = new QAction(tr("Find Next"), this);
  955. m_findNextAct->setToolTip(tr("Find next occurence"));
  956. keySeq = g_config->getShortcutKeySequence("FindNext");
  957. qDebug() << "set FindNext shortcut to" << keySeq;
  958. m_findNextAct->setShortcut(QKeySequence(keySeq));
  959. connect(m_findNextAct, SIGNAL(triggered(bool)),
  960. m_findReplaceDialog, SLOT(findNext()));
  961. m_findPreviousAct = new QAction(tr("Find Previous"), this);
  962. m_findPreviousAct->setToolTip(tr("Find previous occurence"));
  963. keySeq = g_config->getShortcutKeySequence("FindPrevious");
  964. qDebug() << "set FindPrevious shortcut to" << keySeq;
  965. m_findPreviousAct->setShortcut(QKeySequence(keySeq));
  966. connect(m_findPreviousAct, SIGNAL(triggered(bool)),
  967. m_findReplaceDialog, SLOT(findPrevious()));
  968. m_replaceAct = new QAction(tr("Replace"), this);
  969. m_replaceAct->setToolTip(tr("Replace current occurence"));
  970. connect(m_replaceAct, SIGNAL(triggered(bool)),
  971. m_findReplaceDialog, SLOT(replace()));
  972. m_replaceFindAct = new QAction(tr("Replace && Find"), this);
  973. m_replaceFindAct->setToolTip(tr("Replace current occurence and find the next one"));
  974. connect(m_replaceFindAct, SIGNAL(triggered(bool)),
  975. m_findReplaceDialog, SLOT(replaceFind()));
  976. m_replaceAllAct = new QAction(tr("Replace All"), this);
  977. m_replaceAllAct->setToolTip(tr("Replace all occurences in current note"));
  978. connect(m_replaceAllAct, SIGNAL(triggered(bool)),
  979. m_findReplaceDialog, SLOT(replaceAll()));
  980. QAction *searchedWordAct = new QAction(tr("Highlight Searched Pattern"), this);
  981. searchedWordAct->setToolTip(tr("Highlight all occurences of searched pattern"));
  982. searchedWordAct->setCheckable(true);
  983. connect(searchedWordAct, &QAction::triggered,
  984. this, &VMainWindow::changeHighlightSearchedWord);
  985. // Expand Tab into spaces.
  986. QAction *expandTabAct = new QAction(tr("&Expand Tab"), this);
  987. expandTabAct->setToolTip(tr("Expand entered Tab to spaces"));
  988. expandTabAct->setCheckable(true);
  989. connect(expandTabAct, &QAction::triggered,
  990. this, &VMainWindow::changeExpandTab);
  991. // Tab stop width.
  992. QActionGroup *tabStopWidthAct = new QActionGroup(this);
  993. QAction *twoSpaceTabAct = new QAction(tr("2 Spaces"), tabStopWidthAct);
  994. twoSpaceTabAct->setToolTip(tr("Expand Tab to 2 spaces"));
  995. twoSpaceTabAct->setCheckable(true);
  996. twoSpaceTabAct->setData(2);
  997. QAction *fourSpaceTabAct = new QAction(tr("4 Spaces"), tabStopWidthAct);
  998. fourSpaceTabAct->setToolTip(tr("Expand Tab to 4 spaces"));
  999. fourSpaceTabAct->setCheckable(true);
  1000. fourSpaceTabAct->setData(4);
  1001. QAction *eightSpaceTabAct = new QAction(tr("8 Spaces"), tabStopWidthAct);
  1002. eightSpaceTabAct->setToolTip(tr("Expand Tab to 8 spaces"));
  1003. eightSpaceTabAct->setCheckable(true);
  1004. eightSpaceTabAct->setData(8);
  1005. connect(tabStopWidthAct, &QActionGroup::triggered,
  1006. this, &VMainWindow::setTabStopWidth);
  1007. // Auto Indent.
  1008. m_autoIndentAct = new QAction(tr("Auto Indent"), this);
  1009. m_autoIndentAct->setToolTip(tr("Indent automatically when inserting a new line"));
  1010. m_autoIndentAct->setCheckable(true);
  1011. connect(m_autoIndentAct, &QAction::triggered,
  1012. this, &VMainWindow::changeAutoIndent);
  1013. // Auto List.
  1014. QAction *autoListAct = new QAction(tr("Auto List"), this);
  1015. autoListAct->setToolTip(tr("Continue the list automatically when inserting a new line"));
  1016. autoListAct->setCheckable(true);
  1017. connect(autoListAct, &QAction::triggered,
  1018. this, &VMainWindow::changeAutoList);
  1019. // Highlight current cursor line.
  1020. QAction *cursorLineAct = new QAction(tr("Highlight Cursor Line"), this);
  1021. cursorLineAct->setToolTip(tr("Highlight current cursor line"));
  1022. cursorLineAct->setCheckable(true);
  1023. connect(cursorLineAct, &QAction::triggered,
  1024. this, &VMainWindow::changeHighlightCursorLine);
  1025. // Highlight selected word.
  1026. QAction *selectedWordAct = new QAction(tr("Highlight Selected Words"), this);
  1027. selectedWordAct->setToolTip(tr("Highlight all occurences of selected words"));
  1028. selectedWordAct->setCheckable(true);
  1029. connect(selectedWordAct, &QAction::triggered,
  1030. this, &VMainWindow::changeHighlightSelectedWord);
  1031. // Highlight trailing space.
  1032. QAction *trailingSapceAct = new QAction(tr("Highlight Trailing Spaces"), this);
  1033. trailingSapceAct->setToolTip(tr("Highlight all the spaces at the end of a line"));
  1034. trailingSapceAct->setCheckable(true);
  1035. connect(trailingSapceAct, &QAction::triggered,
  1036. this, &VMainWindow::changeHighlightTrailingSapce);
  1037. // Highlight tab.
  1038. QAction *tabAct = new QAction(tr("Highlight Tabs"), this);
  1039. tabAct->setToolTip(tr("Highlight all the tabs"));
  1040. tabAct->setCheckable(true);
  1041. connect(tabAct, &QAction::triggered,
  1042. this, [](bool p_checked) {
  1043. g_config->setEnableTabHighlight(p_checked);
  1044. });
  1045. QMenu *findReplaceMenu = editMenu->addMenu(tr("Find/Replace"));
  1046. findReplaceMenu->setToolTipsVisible(true);
  1047. findReplaceMenu->addAction(m_findReplaceAct);
  1048. findReplaceMenu->addAction(advFindAct);
  1049. findReplaceMenu->addSeparator();
  1050. findReplaceMenu->addAction(m_findNextAct);
  1051. findReplaceMenu->addAction(m_findPreviousAct);
  1052. findReplaceMenu->addAction(m_replaceAct);
  1053. findReplaceMenu->addAction(m_replaceFindAct);
  1054. findReplaceMenu->addAction(m_replaceAllAct);
  1055. findReplaceMenu->addSeparator();
  1056. findReplaceMenu->addAction(searchedWordAct);
  1057. searchedWordAct->setChecked(g_config->getHighlightSearchedWord());
  1058. m_findReplaceAct->setEnabled(false);
  1059. m_findNextAct->setEnabled(false);
  1060. m_findPreviousAct->setEnabled(false);
  1061. m_replaceAct->setEnabled(false);
  1062. m_replaceFindAct->setEnabled(false);
  1063. m_replaceAllAct->setEnabled(false);
  1064. editMenu->addSeparator();
  1065. editMenu->addAction(expandTabAct);
  1066. if (g_config->getIsExpandTab()) {
  1067. expandTabAct->setChecked(true);
  1068. } else {
  1069. expandTabAct->setChecked(false);
  1070. }
  1071. QMenu *tabStopWidthMenu = editMenu->addMenu(tr("Tab Stop Width"));
  1072. tabStopWidthMenu->setToolTipsVisible(true);
  1073. tabStopWidthMenu->addAction(twoSpaceTabAct);
  1074. tabStopWidthMenu->addAction(fourSpaceTabAct);
  1075. tabStopWidthMenu->addAction(eightSpaceTabAct);
  1076. int tabStopWidth = g_config->getTabStopWidth();
  1077. switch (tabStopWidth) {
  1078. case 2:
  1079. twoSpaceTabAct->setChecked(true);
  1080. break;
  1081. case 4:
  1082. fourSpaceTabAct->setChecked(true);
  1083. break;
  1084. case 8:
  1085. eightSpaceTabAct->setChecked(true);
  1086. break;
  1087. default:
  1088. qWarning() << "unsupported tab stop width" << tabStopWidth << "in config";
  1089. }
  1090. editMenu->addAction(m_autoIndentAct);
  1091. m_autoIndentAct->setChecked(g_config->getAutoIndent());
  1092. editMenu->addAction(autoListAct);
  1093. if (g_config->getAutoList()) {
  1094. // Let the trigger handler to trigger m_autoIndentAct, too.
  1095. autoListAct->trigger();
  1096. }
  1097. Q_ASSERT(!(autoListAct->isChecked() && !m_autoIndentAct->isChecked()));
  1098. editMenu->addSeparator();
  1099. initEditorStyleMenu(editMenu);
  1100. initEditorBackgroundMenu(editMenu);
  1101. initEditorLineNumberMenu(editMenu);
  1102. editMenu->addAction(cursorLineAct);
  1103. cursorLineAct->setChecked(g_config->getHighlightCursorLine());
  1104. editMenu->addAction(selectedWordAct);
  1105. selectedWordAct->setChecked(g_config->getHighlightSelectedWord());
  1106. editMenu->addAction(trailingSapceAct);
  1107. trailingSapceAct->setChecked(g_config->getEnableTrailingSpaceHighlight());
  1108. editMenu->addAction(tabAct);
  1109. tabAct->setChecked(g_config->getEnableTabHighlight());
  1110. initAutoScrollCursorLineMenu(editMenu);
  1111. }
  1112. void VMainWindow::initDockWindows()
  1113. {
  1114. setTabPosition(Qt::LeftDockWidgetArea, QTabWidget::West);
  1115. setTabPosition(Qt::RightDockWidgetArea, QTabWidget::East);
  1116. setTabPosition(Qt::TopDockWidgetArea, QTabWidget::North);
  1117. setTabPosition(Qt::BottomDockWidgetArea, QTabWidget::North);
  1118. setDockNestingEnabled(true);
  1119. initToolsDock();
  1120. initSearchDock();
  1121. }
  1122. void VMainWindow::initToolsDock()
  1123. {
  1124. m_toolDock = new QDockWidget(tr("Tools"), this);
  1125. m_toolDock->setObjectName("ToolsDock");
  1126. m_toolDock->setAllowedAreas(Qt::AllDockWidgetAreas);
  1127. // Outline tree.
  1128. outline = new VOutline(this);
  1129. connect(m_editArea, &VEditArea::outlineChanged,
  1130. outline, &VOutline::updateOutline);
  1131. connect(m_editArea, &VEditArea::currentHeaderChanged,
  1132. outline, &VOutline::updateCurrentHeader);
  1133. connect(outline, &VOutline::outlineItemActivated,
  1134. m_editArea, &VEditArea::scrollToHeader);
  1135. // Snippets.
  1136. m_snippetList = new VSnippetList(this);
  1137. // Cart.
  1138. m_cart = new VCart(this);
  1139. m_toolBox = new VToolBox(this);
  1140. m_toolBox->addItem(outline,
  1141. ":/resources/icons/outline.svg",
  1142. tr("Outline"));
  1143. m_toolBox->addItem(m_snippetList,
  1144. ":/resources/icons/snippets.svg",
  1145. tr("Snippets"));
  1146. m_toolBox->addItem(m_cart,
  1147. ":/resources/icons/cart.svg",
  1148. tr("Cart"));
  1149. m_toolDock->setWidget(m_toolBox);
  1150. addDockWidget(Qt::RightDockWidgetArea, m_toolDock);
  1151. QAction *toggleAct = m_toolDock->toggleViewAction();
  1152. toggleAct->setToolTip(tr("Toggle the tools dock widget"));
  1153. VUtils::fixTextWithCaptainShortcut(toggleAct, "ToolsDock");
  1154. m_viewMenu->addAction(toggleAct);
  1155. }
  1156. void VMainWindow::initSearchDock()
  1157. {
  1158. m_searchDock = new QDockWidget(tr("Search"), this);
  1159. m_searchDock->setObjectName("SearchDock");
  1160. m_searchDock->setAllowedAreas(Qt::AllDockWidgetAreas);
  1161. m_searcher = new VSearcher(this);
  1162. m_searchDock->setWidget(m_searcher);
  1163. addDockWidget(Qt::RightDockWidgetArea, m_searchDock);
  1164. QAction *toggleAct = m_searchDock->toggleViewAction();
  1165. toggleAct->setToolTip(tr("Toggle the search dock widget"));
  1166. VUtils::fixTextWithCaptainShortcut(toggleAct, "SearchDock");
  1167. m_viewMenu->addAction(toggleAct);
  1168. }
  1169. void VMainWindow::importNoteFromFile()
  1170. {
  1171. static QString lastPath = QDir::homePath();
  1172. QStringList files = QFileDialog::getOpenFileNames(this,
  1173. tr("Select Files To Create Notes"),
  1174. lastPath);
  1175. if (files.isEmpty()) {
  1176. return;
  1177. }
  1178. // Update lastPath
  1179. lastPath = QFileInfo(files[0]).path();
  1180. QString msg;
  1181. if (!m_fileList->importFiles(files, &msg)) {
  1182. VUtils::showMessage(QMessageBox::Warning,
  1183. tr("Warning"),
  1184. tr("Fail to create notes for all the files."),
  1185. msg,
  1186. QMessageBox::Ok,
  1187. QMessageBox::Ok,
  1188. this);
  1189. } else {
  1190. int cnt = files.size();
  1191. showStatusMessage(tr("%1 %2 created from external files")
  1192. .arg(cnt)
  1193. .arg(cnt > 1 ? tr("notes") : tr("note")));
  1194. }
  1195. }
  1196. void VMainWindow::changeMarkdownConverter(QAction *action)
  1197. {
  1198. if (!action) {
  1199. return;
  1200. }
  1201. MarkdownConverterType type = (MarkdownConverterType)action->data().toInt();
  1202. g_config->setMarkdownConverterType(type);
  1203. }
  1204. void VMainWindow::aboutMessage()
  1205. {
  1206. QString info = tr("VNote");
  1207. info += "<br/>";
  1208. info += tr("Version: %1").arg(VConfigManager::c_version);
  1209. info += "<br/>";
  1210. info += tr("Author: Le Tan (tamlok)");
  1211. info += "<br/><br/>";
  1212. info += tr("VNote is a free and open source Vim-inspired note-taking application that knows programmers and Markdown better.");
  1213. info += "<br/><br/>";
  1214. info += tr("Please visit <a href=\"https://github.com/tamlok/vnote.git\">Github</a> for more information.");
  1215. QMessageBox::about(this, tr("About VNote"), info);
  1216. }
  1217. void VMainWindow::changeExpandTab(bool checked)
  1218. {
  1219. g_config->setIsExpandTab(checked);
  1220. }
  1221. void VMainWindow::enableMermaid(bool p_checked)
  1222. {
  1223. g_config->setEnableMermaid(p_checked);
  1224. VUtils::promptForReopen(this);
  1225. }
  1226. void VMainWindow::enableMathjax(bool p_checked)
  1227. {
  1228. g_config->setEnableMathjax(p_checked);
  1229. VUtils::promptForReopen(this);
  1230. }
  1231. void VMainWindow::changeHighlightCursorLine(bool p_checked)
  1232. {
  1233. g_config->setHighlightCursorLine(p_checked);
  1234. }
  1235. void VMainWindow::changeHighlightSelectedWord(bool p_checked)
  1236. {
  1237. g_config->setHighlightSelectedWord(p_checked);
  1238. }
  1239. void VMainWindow::changeHighlightSearchedWord(bool p_checked)
  1240. {
  1241. g_config->setHighlightSearchedWord(p_checked);
  1242. }
  1243. void VMainWindow::changeHighlightTrailingSapce(bool p_checked)
  1244. {
  1245. g_config->setEnableTrailingSapceHighlight(p_checked);
  1246. }
  1247. void VMainWindow::setTabStopWidth(QAction *action)
  1248. {
  1249. if (!action) {
  1250. return;
  1251. }
  1252. g_config->setTabStopWidth(action->data().toInt());
  1253. }
  1254. void VMainWindow::setEditorBackgroundColor(QAction *action)
  1255. {
  1256. if (!action) {
  1257. return;
  1258. }
  1259. g_config->setCurBackgroundColor(action->data().toString());
  1260. }
  1261. void VMainWindow::initConverterMenu(QMenu *p_menu)
  1262. {
  1263. QMenu *converterMenu = p_menu->addMenu(tr("&Renderer"));
  1264. converterMenu->setToolTipsVisible(true);
  1265. QActionGroup *converterAct = new QActionGroup(this);
  1266. QAction *markedAct = new QAction(tr("Marked"), converterAct);
  1267. markedAct->setToolTip(tr("Use Marked to convert Markdown to HTML (re-open current tabs to make it work)"));
  1268. markedAct->setCheckable(true);
  1269. markedAct->setData(int(MarkdownConverterType::Marked));
  1270. QAction *hoedownAct = new QAction(tr("Hoedown"), converterAct);
  1271. hoedownAct->setToolTip(tr("Use Hoedown to convert Markdown to HTML (re-open current tabs to make it work)"));
  1272. hoedownAct->setCheckable(true);
  1273. hoedownAct->setData(int(MarkdownConverterType::Hoedown));
  1274. QAction *markdownitAct = new QAction(tr("Markdown-it"), converterAct);
  1275. markdownitAct->setToolTip(tr("Use Markdown-it to convert Markdown to HTML (re-open current tabs to make it work)"));
  1276. markdownitAct->setCheckable(true);
  1277. markdownitAct->setData(int(MarkdownConverterType::MarkdownIt));
  1278. QAction *showdownAct = new QAction(tr("Showdown"), converterAct);
  1279. showdownAct->setToolTip(tr("Use Showdown to convert Markdown to HTML (re-open current tabs to make it work)"));
  1280. showdownAct->setCheckable(true);
  1281. showdownAct->setData(int(MarkdownConverterType::Showdown));
  1282. connect(converterAct, &QActionGroup::triggered,
  1283. this, &VMainWindow::changeMarkdownConverter);
  1284. converterMenu->addAction(hoedownAct);
  1285. converterMenu->addAction(markedAct);
  1286. converterMenu->addAction(markdownitAct);
  1287. converterMenu->addAction(showdownAct);
  1288. MarkdownConverterType converterType = g_config->getMdConverterType();
  1289. switch (converterType) {
  1290. case MarkdownConverterType::Marked:
  1291. markedAct->setChecked(true);
  1292. break;
  1293. case MarkdownConverterType::Hoedown:
  1294. hoedownAct->setChecked(true);
  1295. break;
  1296. case MarkdownConverterType::MarkdownIt:
  1297. markdownitAct->setChecked(true);
  1298. break;
  1299. case MarkdownConverterType::Showdown:
  1300. showdownAct->setChecked(true);
  1301. break;
  1302. default:
  1303. Q_ASSERT(false);
  1304. }
  1305. }
  1306. void VMainWindow::initMarkdownitOptionMenu(QMenu *p_menu)
  1307. {
  1308. QMenu *optMenu = p_menu->addMenu(tr("Markdown-it Options"));
  1309. optMenu->setToolTipsVisible(true);
  1310. const MarkdownitOption &opt = g_config->getMarkdownitOption();
  1311. QAction *htmlAct = new QAction(tr("HTML"), this);
  1312. htmlAct->setToolTip(tr("Enable HTML tags in source (re-open current tabs to make it work)"));
  1313. htmlAct->setCheckable(true);
  1314. htmlAct->setChecked(opt.m_html);
  1315. connect(htmlAct, &QAction::triggered,
  1316. this, [](bool p_checked) {
  1317. MarkdownitOption opt = g_config->getMarkdownitOption();
  1318. opt.m_html = p_checked;
  1319. g_config->setMarkdownitOption(opt);
  1320. });
  1321. QAction *breaksAct = new QAction(tr("Line Break"), this);
  1322. breaksAct->setToolTip(tr("Convert '\\n' in paragraphs into line break (re-open current tabs to make it work)"));
  1323. breaksAct->setCheckable(true);
  1324. breaksAct->setChecked(opt.m_breaks);
  1325. connect(breaksAct, &QAction::triggered,
  1326. this, [](bool p_checked) {
  1327. MarkdownitOption opt = g_config->getMarkdownitOption();
  1328. opt.m_breaks = p_checked;
  1329. g_config->setMarkdownitOption(opt);
  1330. });
  1331. QAction *linkifyAct = new QAction(tr("Linkify"), this);
  1332. linkifyAct->setToolTip(tr("Convert URL-like text into links (re-open current tabs to make it work)"));
  1333. linkifyAct->setCheckable(true);
  1334. linkifyAct->setChecked(opt.m_linkify);
  1335. connect(linkifyAct, &QAction::triggered,
  1336. this, [](bool p_checked) {
  1337. MarkdownitOption opt = g_config->getMarkdownitOption();
  1338. opt.m_linkify = p_checked;
  1339. g_config->setMarkdownitOption(opt);
  1340. });
  1341. QAction *supAct = new QAction(tr("Superscript"), this);
  1342. supAct->setToolTip(tr("Enable superscript like ^vnote^ (re-open current tabs to make it work)"));
  1343. supAct->setCheckable(true);
  1344. supAct->setChecked(opt.m_sup);
  1345. connect(supAct, &QAction::triggered,
  1346. this, [](bool p_checked) {
  1347. MarkdownitOption opt = g_config->getMarkdownitOption();
  1348. opt.m_sup = p_checked;
  1349. g_config->setMarkdownitOption(opt);
  1350. });
  1351. QAction *subAct = new QAction(tr("Subscript"), this);
  1352. subAct->setToolTip(tr("Enable subscript like ~vnote~ (re-open current tabs to make it work)"));
  1353. subAct->setCheckable(true);
  1354. subAct->setChecked(opt.m_sub);
  1355. connect(subAct, &QAction::triggered,
  1356. this, [](bool p_checked) {
  1357. MarkdownitOption opt = g_config->getMarkdownitOption();
  1358. opt.m_sub = p_checked;
  1359. g_config->setMarkdownitOption(opt);
  1360. });
  1361. QAction *metadataAct = new QAction(tr("Metadata Aware"), this);
  1362. metadataAct->setToolTip(tr("Be aware of metadata in YAML format (re-open current tabs to make it work)"));
  1363. metadataAct->setCheckable(true);
  1364. metadataAct->setChecked(opt.m_metadata);
  1365. connect(metadataAct, &QAction::triggered,
  1366. this, [](bool p_checked) {
  1367. MarkdownitOption opt = g_config->getMarkdownitOption();
  1368. opt.m_metadata = p_checked;
  1369. g_config->setMarkdownitOption(opt);
  1370. });
  1371. QAction *emojiAct = new QAction(tr("Emoji"), this);
  1372. emojiAct->setToolTip(tr("Enable emoji and emoticon (re-open current tabs to make it work)"));
  1373. emojiAct->setCheckable(true);
  1374. emojiAct->setChecked(opt.m_emoji);
  1375. connect(emojiAct, &QAction::triggered,
  1376. this, [](bool p_checked) {
  1377. MarkdownitOption opt = g_config->getMarkdownitOption();
  1378. opt.m_emoji = p_checked;
  1379. g_config->setMarkdownitOption(opt);
  1380. });
  1381. optMenu->addAction(htmlAct);
  1382. optMenu->addAction(breaksAct);
  1383. optMenu->addAction(linkifyAct);
  1384. optMenu->addAction(supAct);
  1385. optMenu->addAction(subAct);
  1386. optMenu->addAction(metadataAct);
  1387. optMenu->addAction(emojiAct);
  1388. }
  1389. void VMainWindow::initRenderBackgroundMenu(QMenu *menu)
  1390. {
  1391. QActionGroup *renderBackgroundAct = new QActionGroup(this);
  1392. connect(renderBackgroundAct, &QActionGroup::triggered,
  1393. this, &VMainWindow::setRenderBackgroundColor);
  1394. QMenu *renderBgMenu = menu->addMenu(tr("&Rendering Background"));
  1395. renderBgMenu->setToolTipsVisible(true);
  1396. const QString &curBgColor = g_config->getCurRenderBackgroundColor();
  1397. QAction *tmpAct = new QAction(tr("System"), renderBackgroundAct);
  1398. tmpAct->setToolTip(tr("Use system's background color configuration for Markdown rendering"));
  1399. tmpAct->setCheckable(true);
  1400. tmpAct->setData("System");
  1401. if (curBgColor == "System") {
  1402. tmpAct->setChecked(true);
  1403. }
  1404. renderBgMenu->addAction(tmpAct);
  1405. tmpAct = new QAction(tr("Transparent"), renderBackgroundAct);
  1406. tmpAct->setToolTip(tr("Use a transparent background for Markdown rendering"));
  1407. tmpAct->setCheckable(true);
  1408. tmpAct->setData("Transparent");
  1409. if (curBgColor == "Transparent") {
  1410. tmpAct->setChecked(true);
  1411. }
  1412. renderBgMenu->addAction(tmpAct);
  1413. const QVector<VColor> &bgColors = g_config->getCustomColors();
  1414. for (int i = 0; i < bgColors.size(); ++i) {
  1415. tmpAct = new QAction(bgColors[i].m_name, renderBackgroundAct);
  1416. tmpAct->setToolTip(tr("Set as the background color for Markdown rendering "
  1417. "(re-open current tabs to make it work)"));
  1418. tmpAct->setCheckable(true);
  1419. tmpAct->setData(bgColors[i].m_name);
  1420. #if !defined(Q_OS_MACOS) && !defined(Q_OS_MAC)
  1421. QColor color(bgColors[i].m_color);
  1422. QPixmap pixmap(COLOR_PIXMAP_ICON_SIZE, COLOR_PIXMAP_ICON_SIZE);
  1423. pixmap.fill(color);
  1424. tmpAct->setIcon(QIcon(pixmap));
  1425. #endif
  1426. if (curBgColor == bgColors[i].m_name) {
  1427. tmpAct->setChecked(true);
  1428. }
  1429. renderBgMenu->addAction(tmpAct);
  1430. }
  1431. }
  1432. void VMainWindow::initRenderStyleMenu(QMenu *p_menu)
  1433. {
  1434. QMenu *styleMenu = p_menu->addMenu(tr("Rendering &Style"));
  1435. styleMenu->setToolTipsVisible(true);
  1436. QAction *addAct = newAction(VIconUtils::menuIcon(":/resources/icons/add_style.svg"),
  1437. tr("Add Style"),
  1438. styleMenu);
  1439. addAct->setToolTip(tr("Add custom style of read mode"));
  1440. connect(addAct, &QAction::triggered,
  1441. this, [this]() {
  1442. VTipsDialog dialog(VUtils::getDocFile("tips_add_style.md"),
  1443. tr("Add Style"),
  1444. []() {
  1445. QUrl url = QUrl::fromLocalFile(g_config->getStyleConfigFolder());
  1446. QDesktopServices::openUrl(url);
  1447. },
  1448. this);
  1449. dialog.exec();
  1450. });
  1451. styleMenu->addAction(addAct);
  1452. QActionGroup *ag = new QActionGroup(this);
  1453. connect(ag, &QActionGroup::triggered,
  1454. this, [](QAction *p_action) {
  1455. QString data = p_action->data().toString();
  1456. g_config->setCssStyle(data);
  1457. g_vnote->updateTemplate();
  1458. });
  1459. QList<QString> styles = g_config->getCssStyles();
  1460. QString curStyle = g_config->getCssStyle();
  1461. for (auto const &style : styles) {
  1462. QAction *act = new QAction(style, ag);
  1463. act->setToolTip(tr("Set as the CSS style for Markdown rendering "
  1464. "(re-open current tabs to make it work)"));
  1465. act->setCheckable(true);
  1466. act->setData(style);
  1467. // Add it to the menu.
  1468. styleMenu->addAction(act);
  1469. if (curStyle == style) {
  1470. act->setChecked(true);
  1471. }
  1472. }
  1473. }
  1474. void VMainWindow::initCodeBlockStyleMenu(QMenu *p_menu)
  1475. {
  1476. QMenu *styleMenu = p_menu->addMenu(tr("Code Block Style"));
  1477. styleMenu->setToolTipsVisible(true);
  1478. QAction *addAct = newAction(VIconUtils::menuIcon(":/resources/icons/add_style.svg"),
  1479. tr("Add Style"),
  1480. styleMenu);
  1481. addAct->setToolTip(tr("Add custom style of code block in read mode"));
  1482. connect(addAct, &QAction::triggered,
  1483. this, [this]() {
  1484. VTipsDialog dialog(VUtils::getDocFile("tips_add_style.md"),
  1485. tr("Add Style"),
  1486. []() {
  1487. QUrl url = QUrl::fromLocalFile(g_config->getCodeBlockStyleConfigFolder());
  1488. QDesktopServices::openUrl(url);
  1489. },
  1490. this);
  1491. dialog.exec();
  1492. });
  1493. styleMenu->addAction(addAct);
  1494. QActionGroup *ag = new QActionGroup(this);
  1495. connect(ag, &QActionGroup::triggered,
  1496. this, [](QAction *p_action) {
  1497. QString data = p_action->data().toString();
  1498. g_config->setCodeBlockCssStyle(data);
  1499. g_vnote->updateTemplate();
  1500. });
  1501. QList<QString> styles = g_config->getCodeBlockCssStyles();
  1502. QString curStyle = g_config->getCodeBlockCssStyle();
  1503. for (auto const &style : styles) {
  1504. QAction *act = new QAction(style, ag);
  1505. act->setToolTip(tr("Set as the code block CSS style for Markdown rendering "
  1506. "(re-open current tabs to make it work)"));
  1507. act->setCheckable(true);
  1508. act->setData(style);
  1509. // Add it to the menu.
  1510. styleMenu->addAction(act);
  1511. if (curStyle == style) {
  1512. act->setChecked(true);
  1513. }
  1514. }
  1515. }
  1516. void VMainWindow::initEditorBackgroundMenu(QMenu *menu)
  1517. {
  1518. QMenu *backgroundColorMenu = menu->addMenu(tr("&Background Color"));
  1519. backgroundColorMenu->setToolTipsVisible(true);
  1520. QActionGroup *backgroundColorAct = new QActionGroup(this);
  1521. connect(backgroundColorAct, &QActionGroup::triggered,
  1522. this, &VMainWindow::setEditorBackgroundColor);
  1523. // System background color
  1524. const QString &curBgColor = g_config->getCurBackgroundColor();
  1525. QAction *tmpAct = new QAction(tr("System"), backgroundColorAct);
  1526. tmpAct->setToolTip(tr("Use system's background color configuration for editor"));
  1527. tmpAct->setCheckable(true);
  1528. tmpAct->setData("System");
  1529. if (curBgColor == "System") {
  1530. tmpAct->setChecked(true);
  1531. }
  1532. backgroundColorMenu->addAction(tmpAct);
  1533. const QVector<VColor> &bgColors = g_config->getCustomColors();
  1534. for (int i = 0; i < bgColors.size(); ++i) {
  1535. tmpAct = new QAction(bgColors[i].m_name, backgroundColorAct);
  1536. tmpAct->setToolTip(tr("Set as the background color for editor (re-open current tabs to make it work)"));
  1537. tmpAct->setCheckable(true);
  1538. tmpAct->setData(bgColors[i].m_name);
  1539. #if !defined(Q_OS_MACOS) && !defined(Q_OS_MAC)
  1540. QColor color(bgColors[i].m_color);
  1541. QPixmap pixmap(COLOR_PIXMAP_ICON_SIZE, COLOR_PIXMAP_ICON_SIZE);
  1542. pixmap.fill(color);
  1543. tmpAct->setIcon(QIcon(pixmap));
  1544. #endif
  1545. if (curBgColor == bgColors[i].m_name) {
  1546. tmpAct->setChecked(true);
  1547. }
  1548. backgroundColorMenu->addAction(tmpAct);
  1549. }
  1550. }
  1551. void VMainWindow::initEditorLineNumberMenu(QMenu *p_menu)
  1552. {
  1553. QMenu *lineNumMenu = p_menu->addMenu(tr("Line Number"));
  1554. lineNumMenu->setToolTipsVisible(true);
  1555. QActionGroup *lineNumAct = new QActionGroup(lineNumMenu);
  1556. connect(lineNumAct, &QActionGroup::triggered,
  1557. this, [this](QAction *p_action){
  1558. if (!p_action) {
  1559. return;
  1560. }
  1561. g_config->setEditorLineNumber(p_action->data().toInt());
  1562. emit editorConfigUpdated();
  1563. });
  1564. int lineNumberMode = g_config->getEditorLineNumber();
  1565. QAction *act = lineNumAct->addAction(tr("None"));
  1566. act->setToolTip(tr("Do not display line number in edit mode"));
  1567. act->setCheckable(true);
  1568. act->setData(0);
  1569. lineNumMenu->addAction(act);
  1570. if (lineNumberMode == 0) {
  1571. act->setChecked(true);
  1572. }
  1573. act = lineNumAct->addAction(tr("Absolute"));
  1574. act->setToolTip(tr("Display absolute line number in edit mode"));
  1575. act->setCheckable(true);
  1576. act->setData(1);
  1577. lineNumMenu->addAction(act);
  1578. if (lineNumberMode == 1) {
  1579. act->setChecked(true);
  1580. }
  1581. act = lineNumAct->addAction(tr("Relative"));
  1582. act->setToolTip(tr("Display line number relative to current cursor line in edit mode"));
  1583. act->setCheckable(true);
  1584. act->setData(2);
  1585. lineNumMenu->addAction(act);
  1586. if (lineNumberMode == 2) {
  1587. act->setChecked(true);
  1588. }
  1589. act = lineNumAct->addAction(tr("CodeBlock"));
  1590. act->setToolTip(tr("Display line number in code block in edit mode (for Markdown only)"));
  1591. act->setCheckable(true);
  1592. act->setData(3);
  1593. lineNumMenu->addAction(act);
  1594. if (lineNumberMode == 3) {
  1595. act->setChecked(true);
  1596. }
  1597. }
  1598. void VMainWindow::initEditorStyleMenu(QMenu *p_menu)
  1599. {
  1600. QMenu *styleMenu = p_menu->addMenu(tr("Editor &Style"));
  1601. styleMenu->setToolTipsVisible(true);
  1602. QAction *addAct = newAction(VIconUtils::menuIcon(":/resources/icons/add_style.svg"),
  1603. tr("Add Style"),
  1604. styleMenu);
  1605. addAct->setToolTip(tr("Add custom style of editor"));
  1606. connect(addAct, &QAction::triggered,
  1607. this, [this]() {
  1608. VTipsDialog dialog(VUtils::getDocFile("tips_add_style.md"),
  1609. tr("Add Style"),
  1610. []() {
  1611. QUrl url = QUrl::fromLocalFile(g_config->getStyleConfigFolder());
  1612. QDesktopServices::openUrl(url);
  1613. },
  1614. this);
  1615. dialog.exec();
  1616. });
  1617. styleMenu->addAction(addAct);
  1618. QActionGroup *ag = new QActionGroup(this);
  1619. connect(ag, &QActionGroup::triggered,
  1620. this, [](QAction *p_action) {
  1621. QString data = p_action->data().toString();
  1622. g_config->setEditorStyle(data);
  1623. });
  1624. QList<QString> styles = g_config->getEditorStyles();
  1625. QString style = g_config->getEditorStyle();
  1626. for (auto const &item : styles) {
  1627. QAction *act = new QAction(item, ag);
  1628. act->setToolTip(tr("Set as the editor style (re-open current tabs to make it work)"));
  1629. act->setCheckable(true);
  1630. act->setData(item);
  1631. // Add it to the menu.
  1632. styleMenu->addAction(act);
  1633. if (style == item) {
  1634. act->setChecked(true);
  1635. }
  1636. }
  1637. }
  1638. void VMainWindow::initAutoScrollCursorLineMenu(QMenu *p_menu)
  1639. {
  1640. QMenu *subMenu = p_menu->addMenu(tr("Auto Scroll Cursor Line"));
  1641. subMenu->setToolTipsVisible(true);
  1642. QActionGroup *ag = new QActionGroup(this);
  1643. connect(ag, &QActionGroup::triggered,
  1644. this, [](QAction *p_action) {
  1645. g_config->setAutoScrollCursorLine(p_action->data().toInt());
  1646. });
  1647. int mode = g_config->getAutoScrollCursorLine();
  1648. int data = AutoScrollDisabled;
  1649. QAction *act = new QAction(tr("Disabled"), ag);
  1650. act->setCheckable(true);
  1651. act->setData(data);
  1652. subMenu->addAction(act);
  1653. if (mode == data) {
  1654. act->setChecked(true);
  1655. }
  1656. data = AutoScrollEndOfDoc;
  1657. act = new QAction(tr("End Of Document"), ag);
  1658. act->setToolTip(tr("Scroll cursor line into the center when it locates at the end of document"));
  1659. act->setCheckable(true);
  1660. act->setData(data);
  1661. subMenu->addAction(act);
  1662. if (mode == data) {
  1663. act->setChecked(true);
  1664. }
  1665. data = AutoScrollAlways;
  1666. act = new QAction(tr("Always"), ag);
  1667. act->setToolTip(tr("Always scroll cursor line into the center"));
  1668. act->setCheckable(true);
  1669. act->setData(data);
  1670. subMenu->addAction(act);
  1671. if (mode == data) {
  1672. act->setChecked(true);
  1673. }
  1674. }
  1675. void VMainWindow::setRenderBackgroundColor(QAction *action)
  1676. {
  1677. if (!action) {
  1678. return;
  1679. }
  1680. g_config->setCurRenderBackgroundColor(action->data().toString());
  1681. vnote->updateTemplate();
  1682. }
  1683. void VMainWindow::updateActionsStateFromTab(const VEditTab *p_tab)
  1684. {
  1685. const VFile *file = p_tab ? p_tab->getFile() : NULL;
  1686. bool editMode = p_tab ? p_tab->isEditMode() : false;
  1687. bool systemFile = file
  1688. && file->getType() == FileType::Orphan
  1689. && dynamic_cast<const VOrphanFile *>(file)->isSystemFile();
  1690. m_printAct->setEnabled(file && file->getDocType() == DocType::Markdown);
  1691. updateEditReadAct(p_tab);
  1692. saveNoteAct->setEnabled(file && editMode && file->isModifiable());
  1693. deleteNoteAct->setEnabled(file && file->getType() == FileType::Note);
  1694. noteInfoAct->setEnabled(file && !systemFile);
  1695. m_attachmentBtn->setEnabled(file && file->getType() == FileType::Note);
  1696. m_headingBtn->setEnabled(file && editMode);
  1697. setActionsEnabled(m_editToolBar, file && editMode);
  1698. // Handle heading sequence act independently.
  1699. m_headingSequenceAct->setEnabled(editMode
  1700. && file->isModifiable()
  1701. && isHeadingSequenceApplicable());
  1702. const VMdTab *mdTab = dynamic_cast<const VMdTab *>(p_tab);
  1703. m_headingSequenceAct->setChecked(mdTab
  1704. && editMode
  1705. && file->isModifiable()
  1706. && mdTab->isHeadingSequenceEnabled());
  1707. // Find/Replace
  1708. m_findReplaceAct->setEnabled(file);
  1709. m_findNextAct->setEnabled(file);
  1710. m_findPreviousAct->setEnabled(file);
  1711. m_replaceAct->setEnabled(file && editMode);
  1712. m_replaceFindAct->setEnabled(file && editMode);
  1713. m_replaceAllAct->setEnabled(file && editMode);
  1714. if (!file) {
  1715. m_findReplaceDialog->closeDialog();
  1716. }
  1717. m_updateTimer->start();
  1718. }
  1719. void VMainWindow::handleAreaTabStatusUpdated(const VEditTabInfo &p_info)
  1720. {
  1721. if (m_curTab != p_info.m_editTab) {
  1722. if (m_curTab) {
  1723. if (m_vimCmd->isVisible()) {
  1724. m_curTab->handleVimCmdCommandCancelled();
  1725. }
  1726. // Disconnect the trigger signal from edit tab.
  1727. disconnect((VEditTab *)m_curTab, 0, m_vimCmd, 0);
  1728. }
  1729. m_curTab = p_info.m_editTab;
  1730. if (m_curTab) {
  1731. connect((VEditTab *)m_curTab, &VEditTab::triggerVimCmd,
  1732. m_vimCmd, &VVimCmdLineEdit::reset);
  1733. }
  1734. m_vimCmd->hide();
  1735. }
  1736. if (m_curTab) {
  1737. m_curFile = m_curTab->getFile();
  1738. } else {
  1739. m_curFile = NULL;
  1740. }
  1741. if (p_info.m_type == VEditTabInfo::InfoType::All) {
  1742. updateActionsStateFromTab(m_curTab);
  1743. m_attachmentList->setFile(dynamic_cast<VNoteFile *>(m_curFile.data()));
  1744. QString title;
  1745. if (m_curFile) {
  1746. m_findReplaceDialog->updateState(m_curFile->getDocType(),
  1747. m_curTab->isEditMode());
  1748. if (m_curFile->getType() == FileType::Note) {
  1749. const VNoteFile *tmpFile = dynamic_cast<const VNoteFile *>((VFile *)m_curFile);
  1750. title = QString("[%1] %2").arg(tmpFile->getNotebookName()).arg(tmpFile->fetchPath());
  1751. } else {
  1752. title = QString("%1").arg(m_curFile->fetchPath());
  1753. }
  1754. if (!m_curFile->isModifiable()) {
  1755. title.append('#');
  1756. }
  1757. if (m_curTab->isModified()) {
  1758. title.append('*');
  1759. }
  1760. }
  1761. updateWindowTitle(title);
  1762. }
  1763. updateStatusInfo(p_info);
  1764. }
  1765. void VMainWindow::changePanelView(PanelViewState p_state)
  1766. {
  1767. switch (p_state) {
  1768. case PanelViewState::ExpandMode:
  1769. m_mainSplitter->widget(0)->hide();
  1770. m_mainSplitter->widget(1)->show();
  1771. break;
  1772. case PanelViewState::HorizontalMode:
  1773. case PanelViewState::VerticalMode:
  1774. m_mainSplitter->widget(0)->show();
  1775. m_mainSplitter->widget(1)->show();
  1776. break;
  1777. default:
  1778. Q_ASSERT(false);
  1779. break;
  1780. }
  1781. g_config->setPanelViewState((int)p_state);
  1782. expandViewAct->setChecked(p_state == PanelViewState::ExpandMode);
  1783. }
  1784. void VMainWindow::updateWindowTitle(const QString &str)
  1785. {
  1786. QString title = "VNote";
  1787. if (!str.isEmpty()) {
  1788. title = title + " - " + str;
  1789. }
  1790. setWindowTitle(title);
  1791. }
  1792. void VMainWindow::curEditFileInfo()
  1793. {
  1794. Q_ASSERT(m_curFile);
  1795. if (m_curFile->getType() == FileType::Note) {
  1796. VNoteFile *file = dynamic_cast<VNoteFile *>((VFile *)m_curFile);
  1797. Q_ASSERT(file);
  1798. m_fileList->fileInfo(file);
  1799. } else if (m_curFile->getType() == FileType::Orphan) {
  1800. VOrphanFile *file = dynamic_cast<VOrphanFile *>((VFile *)m_curFile);
  1801. Q_ASSERT(file);
  1802. if (!file->isSystemFile()) {
  1803. editOrphanFileInfo(m_curFile);
  1804. }
  1805. }
  1806. }
  1807. void VMainWindow::deleteCurNote()
  1808. {
  1809. if (!m_curFile || m_curFile->getType() != FileType::Note) {
  1810. return;
  1811. }
  1812. VNoteFile *file = dynamic_cast<VNoteFile *>((VFile *)m_curFile);
  1813. m_fileList->deleteFile(file);
  1814. }
  1815. void VMainWindow::closeEvent(QCloseEvent *event)
  1816. {
  1817. bool isExit = m_requestQuit || !g_config->getMinimizeToStystemTray();
  1818. m_requestQuit = false;
  1819. m_captain->exitCaptainMode();
  1820. #if defined(Q_OS_MACOS) || defined(Q_OS_MAC)
  1821. // Do not support minimized to tray on macOS.
  1822. isExit = true;
  1823. #endif
  1824. if (!isExit && g_config->getMinimizeToStystemTray() == -1) {
  1825. // Not initialized yet. Prompt for user.
  1826. int ret = VUtils::showMessage(QMessageBox::Information,
  1827. tr("Close VNote"),
  1828. tr("Do you want to minimize VNote to system tray "
  1829. "instead of quitting it when closing VNote?"),
  1830. tr("You could change the option in Settings later."),
  1831. QMessageBox::Ok | QMessageBox::No | QMessageBox::Cancel,
  1832. QMessageBox::Ok,
  1833. this);
  1834. if (ret == QMessageBox::Ok) {
  1835. g_config->setMinimizeToSystemTray(1);
  1836. } else if (ret == QMessageBox::No) {
  1837. g_config->setMinimizeToSystemTray(0);
  1838. isExit = true;
  1839. } else {
  1840. event->ignore();
  1841. return;
  1842. }
  1843. }
  1844. if (isVisible()) {
  1845. saveStateAndGeometry();
  1846. }
  1847. if (isExit || !m_trayIcon->isVisible()) {
  1848. // Get all the opened tabs.
  1849. bool saveOpenedNotes = g_config->getStartupPageType() == StartupPageType::ContinueLeftOff;
  1850. QVector<VFileSessionInfo> fileInfos;
  1851. QVector<VEditTabInfo> tabs;
  1852. if (saveOpenedNotes) {
  1853. tabs = m_editArea->getAllTabsInfo();
  1854. fileInfos.reserve(tabs.size());
  1855. for (auto const & tab : tabs) {
  1856. // Skip system file.
  1857. VFile *file = tab.m_editTab->getFile();
  1858. if (file->getType() == FileType::Orphan
  1859. && dynamic_cast<VOrphanFile *>(file)->isSystemFile()) {
  1860. continue;
  1861. }
  1862. VFileSessionInfo info = VFileSessionInfo::fromEditTabInfo(&tab);
  1863. if (tab.m_editTab == m_curTab) {
  1864. info.setActive(true);
  1865. }
  1866. fileInfos.push_back(info);
  1867. qDebug() << "file session:" << info.m_file << (info.m_mode == OpenFileMode::Edit);
  1868. }
  1869. }
  1870. if (!m_editArea->closeAllFiles(false)) {
  1871. // Fail to close all the opened files, cancel closing app.
  1872. event->ignore();
  1873. return;
  1874. }
  1875. if (saveOpenedNotes) {
  1876. g_config->setLastOpenedFiles(fileInfos);
  1877. }
  1878. QMainWindow::closeEvent(event);
  1879. qApp->quit();
  1880. } else {
  1881. hide();
  1882. event->ignore();
  1883. }
  1884. }
  1885. void VMainWindow::saveStateAndGeometry()
  1886. {
  1887. g_config->setMainWindowGeometry(saveGeometry());
  1888. g_config->setMainWindowState(saveState());
  1889. g_config->setToolsDockChecked(m_toolDock->isVisible());
  1890. g_config->setSearchDockChecked(m_searchDock->isVisible());
  1891. g_config->setMainSplitterState(m_mainSplitter->saveState());
  1892. g_config->setNotebookSplitterState(m_nbSplitter->saveState());
  1893. m_tagExplorer->saveStateAndGeometry();
  1894. g_config->setNaviBoxCurrentIndex(m_naviBox->currentIndex());
  1895. }
  1896. void VMainWindow::restoreStateAndGeometry()
  1897. {
  1898. const QByteArray geometry = g_config->getMainWindowGeometry();
  1899. if (!geometry.isEmpty()) {
  1900. restoreGeometry(geometry);
  1901. }
  1902. const QByteArray state = g_config->getMainWindowState();
  1903. if (!state.isEmpty()) {
  1904. restoreState(state);
  1905. }
  1906. m_toolDock->setVisible(g_config->getToolsDockChecked());
  1907. m_searchDock->setVisible(g_config->getSearchDockChecked());
  1908. const QByteArray splitterState = g_config->getMainSplitterState();
  1909. if (!splitterState.isEmpty()) {
  1910. m_mainSplitter->restoreState(splitterState);
  1911. }
  1912. const QByteArray nbSplitterState = g_config->getNotebookSplitterState();
  1913. if (!nbSplitterState.isEmpty()) {
  1914. m_nbSplitter->restoreState(nbSplitterState);
  1915. }
  1916. m_naviBox->setCurrentIndex(g_config->getNaviBoxCurrentIndex());
  1917. }
  1918. void VMainWindow::handleCurrentDirectoryChanged(const VDirectory *p_dir)
  1919. {
  1920. newNoteAct->setEnabled(p_dir);
  1921. m_importNoteAct->setEnabled(p_dir);
  1922. }
  1923. void VMainWindow::handleCurrentNotebookChanged(const VNotebook *p_notebook)
  1924. {
  1925. newRootDirAct->setEnabled(p_notebook);
  1926. }
  1927. void VMainWindow::keyPressEvent(QKeyEvent *event)
  1928. {
  1929. int key = event->key();
  1930. Qt::KeyboardModifiers modifiers = event->modifiers();
  1931. if (key == Qt::Key_Escape
  1932. || (key == Qt::Key_BracketLeft
  1933. && modifiers == Qt::ControlModifier)) {
  1934. m_findReplaceDialog->closeDialog();
  1935. event->accept();
  1936. return;
  1937. }
  1938. QMainWindow::keyPressEvent(event);
  1939. }
  1940. bool VMainWindow::locateFile(VFile *p_file)
  1941. {
  1942. bool ret = false;
  1943. if (!p_file || p_file->getType() != FileType::Note) {
  1944. return ret;
  1945. }
  1946. VNoteFile *file = dynamic_cast<VNoteFile *>(p_file);
  1947. VNotebook *notebook = file->getNotebook();
  1948. if (m_notebookSelector->locateNotebook(notebook)) {
  1949. while (m_dirTree->currentNotebook() != notebook) {
  1950. QCoreApplication::sendPostedEvents();
  1951. }
  1952. VDirectory *dir = file->getDirectory();
  1953. if (m_dirTree->locateDirectory(dir)) {
  1954. while (m_fileList->currentDirectory() != dir) {
  1955. QCoreApplication::sendPostedEvents();
  1956. }
  1957. if (m_fileList->locateFile(file)) {
  1958. ret = true;
  1959. m_fileList->setFocus();
  1960. }
  1961. }
  1962. }
  1963. // Open the directory and file panels after location.
  1964. if (ret) {
  1965. showNotebookPanel();
  1966. }
  1967. return ret;
  1968. }
  1969. bool VMainWindow::locateDirectory(VDirectory *p_directory)
  1970. {
  1971. bool ret = false;
  1972. if (!p_directory) {
  1973. return ret;
  1974. }
  1975. VNotebook *notebook = p_directory->getNotebook();
  1976. if (m_notebookSelector->locateNotebook(notebook)) {
  1977. while (m_dirTree->currentNotebook() != notebook) {
  1978. QCoreApplication::sendPostedEvents();
  1979. }
  1980. if (m_dirTree->locateDirectory(p_directory)) {
  1981. ret = true;
  1982. m_dirTree->setFocus();
  1983. }
  1984. }
  1985. // Open the directory and file panels after location.
  1986. if (ret) {
  1987. showNotebookPanel();
  1988. }
  1989. return ret;
  1990. }
  1991. bool VMainWindow::locateNotebook(VNotebook *p_notebook)
  1992. {
  1993. bool ret = false;
  1994. if (!p_notebook) {
  1995. return ret;
  1996. }
  1997. if (m_notebookSelector->locateNotebook(p_notebook)) {
  1998. ret = true;
  1999. m_dirTree->setFocus();
  2000. }
  2001. // Open the directory and file panels after location.
  2002. if (ret) {
  2003. showNotebookPanel();
  2004. }
  2005. return ret;
  2006. }
  2007. void VMainWindow::handleFindDialogTextChanged(const QString &p_text, uint /* p_options */)
  2008. {
  2009. bool enabled = true;
  2010. if (p_text.isEmpty()) {
  2011. enabled = false;
  2012. }
  2013. m_findNextAct->setEnabled(enabled);
  2014. m_findPreviousAct->setEnabled(enabled);
  2015. m_replaceAct->setEnabled(enabled);
  2016. m_replaceFindAct->setEnabled(enabled);
  2017. m_replaceAllAct->setEnabled(enabled);
  2018. }
  2019. void VMainWindow::openFindDialog()
  2020. {
  2021. m_findReplaceDialog->openDialog(m_editArea->getSelectedText());
  2022. }
  2023. void VMainWindow::viewSettings()
  2024. {
  2025. VSettingsDialog settingsDialog(this);
  2026. if (settingsDialog.exec()) {
  2027. if (settingsDialog.getNeedUpdateEditorFont()) {
  2028. updateFontOfAllTabs();
  2029. }
  2030. }
  2031. }
  2032. void VMainWindow::closeCurrentFile()
  2033. {
  2034. if (m_curFile) {
  2035. m_editArea->closeFile(m_curFile, false);
  2036. }
  2037. }
  2038. void VMainWindow::changeAutoIndent(bool p_checked)
  2039. {
  2040. g_config->setAutoIndent(p_checked);
  2041. }
  2042. void VMainWindow::changeAutoList(bool p_checked)
  2043. {
  2044. g_config->setAutoList(p_checked);
  2045. if (p_checked) {
  2046. if (!m_autoIndentAct->isChecked()) {
  2047. m_autoIndentAct->trigger();
  2048. }
  2049. m_autoIndentAct->setEnabled(false);
  2050. } else {
  2051. m_autoIndentAct->setEnabled(true);
  2052. }
  2053. }
  2054. void VMainWindow::enableCodeBlockHighlight(bool p_checked)
  2055. {
  2056. g_config->setEnableCodeBlockHighlight(p_checked);
  2057. }
  2058. void VMainWindow::enableImagePreview(bool p_checked)
  2059. {
  2060. g_config->setEnablePreviewImages(p_checked);
  2061. emit editorConfigUpdated();
  2062. }
  2063. void VMainWindow::enableImagePreviewConstraint(bool p_checked)
  2064. {
  2065. g_config->setEnablePreviewImageConstraint(p_checked);
  2066. emit editorConfigUpdated();
  2067. }
  2068. void VMainWindow::enableImageConstraint(bool p_checked)
  2069. {
  2070. g_config->setEnableImageConstraint(p_checked);
  2071. vnote->updateTemplate();
  2072. }
  2073. void VMainWindow::enableImageCaption(bool p_checked)
  2074. {
  2075. g_config->setEnableImageCaption(p_checked);
  2076. }
  2077. void VMainWindow::shortcutsHelp()
  2078. {
  2079. QString docFile = VUtils::getDocFile(VNote::c_shortcutsDocFile);
  2080. VFile *file = vnote->getFile(docFile, true);
  2081. m_editArea->openFile(file, OpenFileMode::Read);
  2082. }
  2083. void VMainWindow::printNote()
  2084. {
  2085. if (m_printer
  2086. || !m_curFile
  2087. || m_curFile->getDocType() != DocType::Markdown) {
  2088. return;
  2089. }
  2090. m_printer = new QPrinter();
  2091. QPrintDialog dialog(m_printer, this);
  2092. dialog.setWindowTitle(tr("Print Note"));
  2093. V_ASSERT(m_curTab);
  2094. VMdTab *mdTab = dynamic_cast<VMdTab *>((VEditTab *)m_curTab);
  2095. VWebView *webView = mdTab->getWebViewer();
  2096. V_ASSERT(webView);
  2097. if (webView->hasSelection()) {
  2098. dialog.addEnabledOption(QAbstractPrintDialog::PrintSelection);
  2099. }
  2100. if (dialog.exec() == QDialog::Accepted) {
  2101. webView->page()->print(m_printer, [this](bool p_succ) {
  2102. qDebug() << "print web page callback" << p_succ;
  2103. delete m_printer;
  2104. m_printer = NULL;
  2105. });
  2106. } else {
  2107. delete m_printer;
  2108. m_printer = NULL;
  2109. }
  2110. }
  2111. QAction *VMainWindow::newAction(const QIcon &p_icon,
  2112. const QString &p_text,
  2113. QObject *p_parent)
  2114. {
  2115. #if defined(Q_OS_MACOS) || defined(Q_OS_MAC)
  2116. Q_UNUSED(p_icon);
  2117. return new QAction(p_text, p_parent);
  2118. #else
  2119. return new QAction(p_icon, p_text, p_parent);
  2120. #endif
  2121. }
  2122. void VMainWindow::showStatusMessage(const QString &p_msg)
  2123. {
  2124. const int timeout = 5000;
  2125. statusBar()->showMessage(p_msg, timeout);
  2126. }
  2127. void VMainWindow::updateStatusInfo(const VEditTabInfo &p_info)
  2128. {
  2129. if (m_curTab) {
  2130. m_tabIndicator->update(p_info);
  2131. m_tabIndicator->show();
  2132. if (m_curTab->isEditMode()) {
  2133. if (p_info.m_type == VEditTabInfo::InfoType::All) {
  2134. m_curTab->requestUpdateVimStatus();
  2135. }
  2136. } else {
  2137. m_vimIndicator->hide();
  2138. }
  2139. } else {
  2140. m_tabIndicator->hide();
  2141. m_vimIndicator->hide();
  2142. }
  2143. }
  2144. void VMainWindow::handleVimStatusUpdated(const VVim *p_vim)
  2145. {
  2146. m_vimIndicator->update(p_vim);
  2147. if (!p_vim || !m_curTab || !m_curTab->isEditMode()) {
  2148. m_vimIndicator->hide();
  2149. } else {
  2150. m_vimIndicator->show();
  2151. }
  2152. }
  2153. bool VMainWindow::tryOpenInternalFile(const QString &p_filePath)
  2154. {
  2155. if (p_filePath.isEmpty()) {
  2156. return false;
  2157. }
  2158. if (QFileInfo::exists(p_filePath)) {
  2159. VFile *file = vnote->getInternalFile(p_filePath);
  2160. if (file) {
  2161. m_editArea->openFile(file, OpenFileMode::Read);
  2162. return true;
  2163. }
  2164. }
  2165. return false;
  2166. }
  2167. QVector<VFile *> VMainWindow::openFiles(const QStringList &p_files,
  2168. bool p_forceOrphan,
  2169. OpenFileMode p_mode,
  2170. bool p_forceMode,
  2171. bool p_oneByOne)
  2172. {
  2173. QVector<VFile *> vfiles;
  2174. vfiles.reserve(p_files.size());
  2175. for (int i = 0; i < p_files.size(); ++i) {
  2176. if (!QFileInfo::exists(p_files[i])) {
  2177. qWarning() << "file" << p_files[i] << "does not exist";
  2178. continue;
  2179. }
  2180. VFile *file = vnote->getFile(p_files[i], p_forceOrphan);
  2181. m_editArea->openFile(file, p_mode, p_forceMode);
  2182. vfiles.append(file);
  2183. if (p_oneByOne) {
  2184. QCoreApplication::sendPostedEvents();
  2185. }
  2186. }
  2187. return vfiles;
  2188. }
  2189. void VMainWindow::editOrphanFileInfo(VFile *p_file)
  2190. {
  2191. VOrphanFile *file = dynamic_cast<VOrphanFile *>(p_file);
  2192. Q_ASSERT(file);
  2193. VOrphanFileInfoDialog dialog(file, this);
  2194. if (dialog.exec() == QDialog::Accepted) {
  2195. QString imgFolder = dialog.getImageFolder();
  2196. file->setImageFolder(imgFolder);
  2197. }
  2198. }
  2199. void VMainWindow::checkSharedMemory()
  2200. {
  2201. QStringList files = m_guard->fetchFilesToOpen();
  2202. if (!files.isEmpty()) {
  2203. qDebug() << "shared memory fetch files" << files;
  2204. openFiles(files, false, g_config->getNoteOpenMode(), false, false);
  2205. // Eliminate the signal.
  2206. m_guard->fetchAskedToShow();
  2207. showMainWindow();
  2208. } else if (m_guard->fetchAskedToShow()) {
  2209. qDebug() << "shared memory asked to show up";
  2210. showMainWindow();
  2211. }
  2212. }
  2213. void VMainWindow::initTrayIcon()
  2214. {
  2215. QMenu *menu = new QMenu(this);
  2216. QAction *showMainWindowAct = menu->addAction(tr("Show VNote"));
  2217. connect(showMainWindowAct, &QAction::triggered,
  2218. this, &VMainWindow::showMainWindow);
  2219. QAction *exitAct = menu->addAction(tr("Quit"));
  2220. connect(exitAct, &QAction::triggered,
  2221. this, &VMainWindow::quitApp);
  2222. QIcon sysIcon(":/resources/icons/256x256/vnote.png");
  2223. #if defined(Q_OS_MACOS) || defined(Q_OS_MAC)
  2224. sysIcon.setIsMask(true);
  2225. #endif
  2226. m_trayIcon = new QSystemTrayIcon(sysIcon, this);
  2227. m_trayIcon->setToolTip(tr("VNote"));
  2228. m_trayIcon->setContextMenu(menu);
  2229. connect(m_trayIcon, &QSystemTrayIcon::activated,
  2230. this, [this](QSystemTrayIcon::ActivationReason p_reason){
  2231. if (p_reason == QSystemTrayIcon::Trigger) {
  2232. this->showMainWindow();
  2233. }
  2234. });
  2235. m_trayIcon->show();
  2236. }
  2237. void VMainWindow::changeEvent(QEvent *p_event)
  2238. {
  2239. if (p_event->type() == QEvent::WindowStateChange) {
  2240. QWindowStateChangeEvent *eve = dynamic_cast<QWindowStateChangeEvent *>(p_event);
  2241. m_windowOldState = eve->oldState();
  2242. }
  2243. QMainWindow::changeEvent(p_event);
  2244. }
  2245. void VMainWindow::showMainWindow()
  2246. {
  2247. if (this->isMinimized()) {
  2248. if (m_windowOldState & Qt::WindowMaximized) {
  2249. this->showMaximized();
  2250. } else if (m_windowOldState & Qt::WindowFullScreen) {
  2251. this->showFullScreen();
  2252. } else {
  2253. this->showNormal();
  2254. }
  2255. } else {
  2256. this->show();
  2257. // Need to call raise() in macOS.
  2258. this->raise();
  2259. }
  2260. this->activateWindow();
  2261. }
  2262. void VMainWindow::openStartupPages()
  2263. {
  2264. StartupPageType type = g_config->getStartupPageType();
  2265. switch (type) {
  2266. case StartupPageType::ContinueLeftOff:
  2267. {
  2268. QVector<VFileSessionInfo> files = g_config->getLastOpenedFiles();
  2269. qDebug() << "open" << files.size() << "last opened files";
  2270. m_editArea->openFiles(files, true);
  2271. break;
  2272. }
  2273. case StartupPageType::SpecificPages:
  2274. {
  2275. QStringList pagesToOpen = VUtils::filterFilePathsToOpen(g_config->getStartupPages());
  2276. qDebug() << "open startup pages" << pagesToOpen;
  2277. openFiles(pagesToOpen, false, g_config->getNoteOpenMode(), false, true);
  2278. break;
  2279. }
  2280. default:
  2281. break;
  2282. }
  2283. }
  2284. bool VMainWindow::isHeadingSequenceApplicable() const
  2285. {
  2286. if (!m_curTab) {
  2287. return false;
  2288. }
  2289. Q_ASSERT(m_curFile);
  2290. if (!m_curFile->isModifiable()
  2291. || m_curFile->getDocType() != DocType::Markdown) {
  2292. return false;
  2293. }
  2294. return true;
  2295. }
  2296. // Popup the attachment list if it is enabled.
  2297. bool VMainWindow::showAttachmentListByCaptain(void *p_target, void *p_data)
  2298. {
  2299. Q_UNUSED(p_data);
  2300. VMainWindow *obj = static_cast<VMainWindow *>(p_target);
  2301. if (obj->m_attachmentBtn->isEnabled()) {
  2302. // Show tool bar first.
  2303. bool toolBarChecked = obj->m_toolBarAct->isChecked();
  2304. if (!toolBarChecked) {
  2305. obj->setToolBarVisible(true);
  2306. // Make it visible first.
  2307. QCoreApplication::sendPostedEvents();
  2308. }
  2309. obj->m_attachmentBtn->showPopupWidget();
  2310. if (!toolBarChecked) {
  2311. obj->setToolBarVisible(false);
  2312. }
  2313. }
  2314. return true;
  2315. }
  2316. bool VMainWindow::locateCurrentFileByCaptain(void *p_target, void *p_data)
  2317. {
  2318. Q_UNUSED(p_data);
  2319. VMainWindow *obj = static_cast<VMainWindow *>(p_target);
  2320. if (obj->m_curFile) {
  2321. if (obj->locateFile(obj->m_curFile)) {
  2322. return false;
  2323. }
  2324. }
  2325. return true;
  2326. }
  2327. bool VMainWindow::toggleExpandModeByCaptain(void *p_target, void *p_data)
  2328. {
  2329. Q_UNUSED(p_data);
  2330. VMainWindow *obj = static_cast<VMainWindow *>(p_target);
  2331. obj->expandViewAct->trigger();
  2332. return true;
  2333. }
  2334. bool VMainWindow::discardAndReadByCaptain(void *p_target, void *p_data)
  2335. {
  2336. Q_UNUSED(p_data);
  2337. VMainWindow *obj = static_cast<VMainWindow *>(p_target);
  2338. if (obj->m_curTab) {
  2339. obj->m_discardExitAct->trigger();
  2340. obj->m_curTab->setFocus();
  2341. return false;
  2342. }
  2343. return true;
  2344. }
  2345. bool VMainWindow::toggleToolBarByCaptain(void *p_target, void *p_data)
  2346. {
  2347. Q_UNUSED(p_data);
  2348. VMainWindow *obj = static_cast<VMainWindow *>(p_target);
  2349. obj->m_toolBarAct->trigger();
  2350. return true;
  2351. }
  2352. bool VMainWindow::toggleToolsDockByCaptain(void *p_target, void *p_data)
  2353. {
  2354. Q_UNUSED(p_data);
  2355. VMainWindow *obj = static_cast<VMainWindow *>(p_target);
  2356. obj->m_toolDock->setVisible(!obj->m_toolDock->isVisible());
  2357. return true;
  2358. }
  2359. bool VMainWindow::toggleSearchDockByCaptain(void *p_target, void *p_data)
  2360. {
  2361. Q_UNUSED(p_data);
  2362. VMainWindow *obj = static_cast<VMainWindow *>(p_target);
  2363. bool visible = obj->m_searchDock->isVisible();
  2364. obj->m_searchDock->setVisible(!visible);
  2365. if (!visible) {
  2366. obj->m_searcher->focusToSearch();
  2367. return false;
  2368. }
  2369. return true;
  2370. }
  2371. bool VMainWindow::closeFileByCaptain(void *p_target, void *p_data)
  2372. {
  2373. Q_UNUSED(p_data);
  2374. VMainWindow *obj = static_cast<VMainWindow *>(p_target);
  2375. obj->closeCurrentFile();
  2376. QWidget *nextFocus = obj->m_editArea->getCurrentTab();
  2377. if (nextFocus) {
  2378. nextFocus->setFocus();
  2379. } else {
  2380. obj->m_fileList->setFocus();
  2381. }
  2382. return false;
  2383. }
  2384. bool VMainWindow::shortcutsHelpByCaptain(void *p_target, void *p_data)
  2385. {
  2386. Q_UNUSED(p_data);
  2387. VMainWindow *obj = static_cast<VMainWindow *>(p_target);
  2388. obj->shortcutsHelp();
  2389. return false;
  2390. }
  2391. bool VMainWindow::flushLogFileByCaptain(void *p_target, void *p_data)
  2392. {
  2393. Q_UNUSED(p_target);
  2394. Q_UNUSED(p_data);
  2395. #if defined(QT_NO_DEBUG)
  2396. // Flush g_logFile.
  2397. g_logFile.flush();
  2398. #endif
  2399. return true;
  2400. }
  2401. bool VMainWindow::exportByCaptain(void *p_target, void *p_data)
  2402. {
  2403. Q_UNUSED(p_data);
  2404. VMainWindow *obj = static_cast<VMainWindow *>(p_target);
  2405. QTimer::singleShot(50, obj, SLOT(handleExportAct()));
  2406. return true;
  2407. }
  2408. bool VMainWindow::focusEditAreaByCaptain(void *p_target, void *p_data)
  2409. {
  2410. Q_UNUSED(p_data);
  2411. VMainWindow *obj = static_cast<VMainWindow *>(p_target);
  2412. obj->focusEditArea();
  2413. return false;
  2414. }
  2415. void VMainWindow::promptNewNotebookIfEmpty()
  2416. {
  2417. if (vnote->getNotebooks().isEmpty()) {
  2418. m_notebookSelector->newNotebook();
  2419. }
  2420. }
  2421. void VMainWindow::initShortcuts()
  2422. {
  2423. QString keySeq = g_config->getShortcutKeySequence("CloseNote");
  2424. qDebug() << "set CloseNote shortcut to" << keySeq;
  2425. if (!keySeq.isEmpty()) {
  2426. QShortcut *closeNoteShortcut = new QShortcut(QKeySequence(keySeq), this);
  2427. closeNoteShortcut->setContext(Qt::WidgetWithChildrenShortcut);
  2428. connect(closeNoteShortcut, &QShortcut::activated,
  2429. this, &VMainWindow::closeCurrentFile);
  2430. }
  2431. }
  2432. void VMainWindow::openFlashPage()
  2433. {
  2434. openFiles(QStringList() << g_config->getFlashPage(),
  2435. false,
  2436. OpenFileMode::Edit,
  2437. true);
  2438. }
  2439. void VMainWindow::openQuickAccess()
  2440. {
  2441. const QString &qaPath = g_config->getQuickAccess();
  2442. if (qaPath.isEmpty()) {
  2443. VUtils::showMessage(QMessageBox::Information,
  2444. tr("Information"),
  2445. tr("Quick Access is not set."),
  2446. tr("Please specify the note for Quick Access in the settings dialog "
  2447. "or the context menu of a note."),
  2448. QMessageBox::Ok,
  2449. QMessageBox::Ok,
  2450. this);
  2451. return;
  2452. }
  2453. openFiles(QStringList(qaPath), false, g_config->getNoteOpenMode());
  2454. }
  2455. void VMainWindow::initHeadingButton(QToolBar *p_tb)
  2456. {
  2457. m_headingBtn = new QPushButton(VIconUtils::toolButtonIcon(":/resources/icons/heading.svg"),
  2458. "",
  2459. this);
  2460. m_headingBtn->setToolTip(tr("Headings"));
  2461. m_headingBtn->setProperty("CornerBtn", true);
  2462. m_headingBtn->setFocusPolicy(Qt::NoFocus);
  2463. m_headingBtn->setEnabled(false);
  2464. QMenu *menu = new QMenu(this);
  2465. QString text(tr("Heading %1"));
  2466. QString tooltip(tr("Heading %1\t%2"));
  2467. QWidgetAction *wact = new QWidgetAction(menu);
  2468. wact->setData(1);
  2469. VButtonMenuItem *w = new VButtonMenuItem(wact, text.arg(1), this);
  2470. w->setToolTip(tooltip.arg(1).arg(VUtils::getShortcutText("Ctrl+1")));
  2471. w->setProperty("Heading1", true);
  2472. wact->setDefaultWidget(w);
  2473. menu->addAction(wact);
  2474. wact = new QWidgetAction(menu);
  2475. wact->setData(2);
  2476. w = new VButtonMenuItem(wact, text.arg(2), this);
  2477. w->setToolTip(tooltip.arg(2).arg(VUtils::getShortcutText("Ctrl+2")));
  2478. w->setProperty("Heading2", true);
  2479. wact->setDefaultWidget(w);
  2480. menu->addAction(wact);
  2481. wact = new QWidgetAction(menu);
  2482. wact->setData(3);
  2483. w = new VButtonMenuItem(wact, text.arg(3), this);
  2484. w->setToolTip(tooltip.arg(3).arg(VUtils::getShortcutText("Ctrl+3")));
  2485. w->setProperty("Heading3", true);
  2486. wact->setDefaultWidget(w);
  2487. menu->addAction(wact);
  2488. wact = new QWidgetAction(menu);
  2489. wact->setData(4);
  2490. w = new VButtonMenuItem(wact, text.arg(4), this);
  2491. w->setToolTip(tooltip.arg(4).arg(VUtils::getShortcutText("Ctrl+4")));
  2492. w->setProperty("Heading4", true);
  2493. wact->setDefaultWidget(w);
  2494. menu->addAction(wact);
  2495. wact = new QWidgetAction(menu);
  2496. wact->setData(5);
  2497. w = new VButtonMenuItem(wact, text.arg(5), this);
  2498. w->setToolTip(tooltip.arg(5).arg(VUtils::getShortcutText("Ctrl+5")));
  2499. w->setProperty("Heading5", true);
  2500. wact->setDefaultWidget(w);
  2501. menu->addAction(wact);
  2502. wact = new QWidgetAction(menu);
  2503. wact->setData(6);
  2504. w = new VButtonMenuItem(wact, text.arg(6), this);
  2505. w->setToolTip(tooltip.arg(6).arg(VUtils::getShortcutText("Ctrl+6")));
  2506. w->setProperty("Heading6", true);
  2507. wact->setDefaultWidget(w);
  2508. menu->addAction(wact);
  2509. wact = new QWidgetAction(menu);
  2510. wact->setData(0);
  2511. w = new VButtonMenuItem(wact, tr("Clear"), this);
  2512. w->setToolTip(tr("Clear\t%1").arg(VUtils::getShortcutText("Ctrl+7")));
  2513. wact->setDefaultWidget(w);
  2514. menu->addAction(wact);
  2515. connect(menu, &QMenu::triggered,
  2516. this, [this, menu](QAction *p_action) {
  2517. if (m_curTab) {
  2518. int level = p_action->data().toInt();
  2519. m_curTab->decorateText(TextDecoration::Heading, level);
  2520. }
  2521. menu->hide();
  2522. });
  2523. m_headingBtn->setMenu(menu);
  2524. p_tb->addWidget(m_headingBtn);
  2525. }
  2526. void VMainWindow::initThemeMenu(QMenu *p_menu)
  2527. {
  2528. QMenu *themeMenu = p_menu->addMenu(tr("Theme"));
  2529. themeMenu->setToolTipsVisible(true);
  2530. QAction *addAct = newAction(VIconUtils::menuIcon(":/resources/icons/add_style.svg"),
  2531. tr("Add Theme"),
  2532. themeMenu);
  2533. addAct->setToolTip(tr("Add custom theme"));
  2534. connect(addAct, &QAction::triggered,
  2535. this, [this]() {
  2536. VTipsDialog dialog(VUtils::getDocFile("tips_add_theme.md"),
  2537. tr("Add Theme"),
  2538. []() {
  2539. QUrl url = QUrl::fromLocalFile(g_config->getThemeConfigFolder());
  2540. QDesktopServices::openUrl(url);
  2541. },
  2542. this);
  2543. dialog.exec();
  2544. });
  2545. themeMenu->addAction(addAct);
  2546. QActionGroup *ag = new QActionGroup(this);
  2547. connect(ag, &QActionGroup::triggered,
  2548. this, [](QAction *p_action) {
  2549. QString data = p_action->data().toString();
  2550. g_config->setTheme(data);
  2551. });
  2552. QList<QString> themes = g_config->getThemes();
  2553. QString theme = g_config->getTheme();
  2554. for (auto const &item : themes) {
  2555. QAction *act = new QAction(item, ag);
  2556. act->setToolTip(tr("Set as the theme of VNote (restart VNote to make it work)"));
  2557. act->setCheckable(true);
  2558. act->setData(item);
  2559. // Add it to the menu.
  2560. themeMenu->addAction(act);
  2561. if (theme == item) {
  2562. act->setChecked(true);
  2563. }
  2564. }
  2565. }
  2566. void VMainWindow::customShortcut()
  2567. {
  2568. VTipsDialog dialog(VUtils::getDocFile("tips_custom_shortcut.md"),
  2569. tr("Customize Shortcuts"),
  2570. []() {
  2571. #if defined(Q_OS_MACOS) || defined(Q_OS_MAC)
  2572. // On macOS, it seems that we could not open that ini file directly.
  2573. QUrl url = QUrl::fromLocalFile(g_config->getConfigFolder());
  2574. #else
  2575. QUrl url = QUrl::fromLocalFile(g_config->getConfigFilePath());
  2576. #endif
  2577. QDesktopServices::openUrl(url);
  2578. },
  2579. this);
  2580. dialog.exec();
  2581. }
  2582. void VMainWindow::initVimCmd()
  2583. {
  2584. m_vimCmd = new VVimCmdLineEdit(this);
  2585. m_vimCmd->setProperty("VimCommandLine", true);
  2586. connect(m_vimCmd, &VVimCmdLineEdit::commandCancelled,
  2587. this, [this]() {
  2588. if (m_curTab) {
  2589. m_curTab->focusTab();
  2590. }
  2591. // NOTICE: should not hide before setting focus to edit tab.
  2592. m_vimCmd->hide();
  2593. if (m_curTab) {
  2594. m_curTab->handleVimCmdCommandCancelled();
  2595. }
  2596. });
  2597. connect(m_vimCmd, &VVimCmdLineEdit::commandFinished,
  2598. this, [this](VVim::CommandLineType p_type, const QString &p_cmd) {
  2599. if (m_curTab) {
  2600. m_curTab->focusTab();
  2601. }
  2602. m_vimCmd->hide();
  2603. // Hide the cmd line edit before execute the command.
  2604. // If we execute the command first, we will get Chinese input
  2605. // method enabled after returning to read mode.
  2606. if (m_curTab) {
  2607. m_curTab->handleVimCmdCommandFinished(p_type, p_cmd);
  2608. }
  2609. });
  2610. connect(m_vimCmd, &VVimCmdLineEdit::commandChanged,
  2611. this, [this](VVim::CommandLineType p_type, const QString &p_cmd) {
  2612. if (m_curTab) {
  2613. m_curTab->handleVimCmdCommandChanged(p_type, p_cmd);
  2614. }
  2615. });
  2616. connect(m_vimCmd, &VVimCmdLineEdit::requestNextCommand,
  2617. this, [this](VVim::CommandLineType p_type, const QString &p_cmd) {
  2618. if (m_curTab) {
  2619. QString cmd = m_curTab->handleVimCmdRequestNextCommand(p_type, p_cmd);
  2620. if (!cmd.isNull()) {
  2621. m_vimCmd->setCommand(cmd);
  2622. } else {
  2623. m_vimCmd->restoreUserLastInput();
  2624. }
  2625. }
  2626. });
  2627. connect(m_vimCmd, &VVimCmdLineEdit::requestPreviousCommand,
  2628. this, [this](VVim::CommandLineType p_type, const QString &p_cmd) {
  2629. if (m_curTab) {
  2630. QString cmd = m_curTab->handleVimCmdRequestPreviousCommand(p_type, p_cmd);
  2631. if (!cmd.isNull()) {
  2632. m_vimCmd->setCommand(cmd);
  2633. }
  2634. }
  2635. });
  2636. connect(m_vimCmd, &VVimCmdLineEdit::requestRegister,
  2637. this, [this](int p_key, int p_modifiers){
  2638. if (m_curTab) {
  2639. QString val = m_curTab->handleVimCmdRequestRegister(p_key, p_modifiers);
  2640. if (!val.isEmpty()) {
  2641. m_vimCmd->setText(m_vimCmd->text() + val);
  2642. }
  2643. }
  2644. });
  2645. m_vimCmd->hide();
  2646. }
  2647. void VMainWindow::toggleEditReadMode()
  2648. {
  2649. if (!m_curTab) {
  2650. return;
  2651. }
  2652. if (m_curTab->isEditMode()) {
  2653. // Save changes and read.
  2654. m_editArea->saveAndReadFile();
  2655. } else {
  2656. // Edit.
  2657. m_editArea->editFile();
  2658. }
  2659. }
  2660. void VMainWindow::updateEditReadAct(const VEditTab *p_tab)
  2661. {
  2662. static QIcon editIcon = VIconUtils::toolButtonIcon(":/resources/icons/edit_note.svg");
  2663. static QString editText;
  2664. static QIcon readIcon = VIconUtils::toolButtonIcon(":/resources/icons/save_exit.svg");
  2665. static QString readText;
  2666. if (editText.isEmpty()) {
  2667. QString keySeq = g_config->getShortcutKeySequence("EditReadNote");
  2668. QKeySequence seq(keySeq);
  2669. if (!seq.isEmpty()) {
  2670. QString shortcutText = VUtils::getShortcutText(keySeq);
  2671. editText = tr("Edit\t%1").arg(shortcutText);
  2672. readText = tr("Save Changes And Read\t%1").arg(shortcutText);
  2673. m_editReadAct->setShortcut(seq);
  2674. } else {
  2675. editText = tr("Edit");
  2676. readText = tr("Save Changes And Read");
  2677. }
  2678. }
  2679. if (!p_tab || !p_tab->isEditMode()) {
  2680. // Edit.
  2681. m_editReadAct->setIcon(editIcon);
  2682. m_editReadAct->setText(editText);
  2683. m_editReadAct->setStatusTip(tr("Edit current note"));
  2684. m_discardExitAct->setEnabled(false);
  2685. } else {
  2686. // Read.
  2687. m_editReadAct->setIcon(readIcon);
  2688. m_editReadAct->setText(readText);
  2689. m_editReadAct->setStatusTip(tr("Save changes and exit edit mode"));
  2690. m_discardExitAct->setEnabled(true);
  2691. }
  2692. m_editReadAct->setEnabled(p_tab);
  2693. }
  2694. void VMainWindow::handleExportAct()
  2695. {
  2696. VExportDialog dialog(m_notebookSelector->currentNotebook(),
  2697. m_dirTree->currentDirectory(),
  2698. m_curFile,
  2699. m_cart,
  2700. g_config->getMdConverterType(),
  2701. this);
  2702. dialog.exec();
  2703. }
  2704. VNotebook *VMainWindow::getCurrentNotebook() const
  2705. {
  2706. return m_notebookSelector->currentNotebook();
  2707. }
  2708. void VMainWindow::activateUniversalEntry()
  2709. {
  2710. if (!m_ue) {
  2711. initUniversalEntry();
  2712. }
  2713. m_captain->setCaptainModeEnabled(false);
  2714. // Move it to the top left corner of edit area.
  2715. QPoint topLeft = m_editArea->mapToGlobal(QPoint(0, 0));
  2716. QRect eaRect = m_editArea->editAreaRect();
  2717. topLeft += eaRect.topLeft();
  2718. // Use global position.
  2719. m_ue->move(topLeft);
  2720. eaRect.moveTop(0);
  2721. m_ue->setAvailableRect(eaRect);
  2722. m_ue->show();
  2723. m_ue->raise();
  2724. }
  2725. void VMainWindow::initUniversalEntry()
  2726. {
  2727. m_ue = new VUniversalEntry(this);
  2728. m_ue->hide();
  2729. #if defined(Q_OS_MACOS) || defined(Q_OS_MAC)
  2730. // Qt::Popup on macOS does not work well with input method.
  2731. m_ue->setWindowFlags(Qt::Tool
  2732. | Qt::NoDropShadowWindowHint);
  2733. m_ue->setWindowModality(Qt::ApplicationModal);
  2734. #else
  2735. m_ue->setWindowFlags(Qt::Popup
  2736. | Qt::FramelessWindowHint
  2737. | Qt::NoDropShadowWindowHint);
  2738. #endif
  2739. connect(m_ue, &VUniversalEntry::exited,
  2740. this, [this]() {
  2741. m_captain->setCaptainModeEnabled(true);
  2742. });
  2743. // Register entries.
  2744. VSearchUE *searchUE = new VSearchUE(this);
  2745. m_ue->registerEntry('q', searchUE, VSearchUE::Name_FolderNote_AllNotebook);
  2746. m_ue->registerEntry('a', searchUE, VSearchUE::Content_Note_AllNotebook);
  2747. m_ue->registerEntry('z', searchUE, VSearchUE::Tag_Note_AllNotebook);
  2748. m_ue->registerEntry('w', searchUE, VSearchUE::Name_Notebook_AllNotebook);
  2749. m_ue->registerEntry('e', searchUE, VSearchUE::Name_FolderNote_CurrentNotebook);
  2750. m_ue->registerEntry('d', searchUE, VSearchUE::Content_Note_CurrentNotebook);
  2751. m_ue->registerEntry('c', searchUE, VSearchUE::Tag_Note_CurrentNotebook);
  2752. m_ue->registerEntry('r', searchUE, VSearchUE::Name_FolderNote_CurrentFolder);
  2753. m_ue->registerEntry('f', searchUE, VSearchUE::Content_Note_CurrentFolder);
  2754. m_ue->registerEntry('v', searchUE, VSearchUE::Tag_Note_CurrentFolder);
  2755. m_ue->registerEntry('t', searchUE, VSearchUE::Name_Note_Buffer);
  2756. m_ue->registerEntry('g', searchUE, VSearchUE::Content_Note_Buffer);
  2757. m_ue->registerEntry('b', searchUE, VSearchUE::Outline_Note_Buffer);
  2758. m_ue->registerEntry('u', searchUE, VSearchUE::Content_Note_ExplorerDirectory);
  2759. m_ue->registerEntry('y', new VOutlineUE(this), 0);
  2760. m_ue->registerEntry('h', searchUE, VSearchUE::Path_FolderNote_AllNotebook);
  2761. m_ue->registerEntry('n', searchUE, VSearchUE::Path_FolderNote_CurrentNotebook);
  2762. m_ue->registerEntry('m', new VListFolderUE(this), 0);
  2763. m_ue->registerEntry('j', new VListUE(this), VListUE::History);
  2764. m_ue->registerEntry('?', new VHelpUE(this), 0);
  2765. }
  2766. void VMainWindow::checkNotebooks()
  2767. {
  2768. bool updated = false;
  2769. QVector<VNotebook *> &notebooks = g_vnote->getNotebooks();
  2770. for (int i = 0; i < notebooks.size(); ++i) {
  2771. VNotebook *nb = notebooks[i];
  2772. if (nb->isValid()) {
  2773. continue;
  2774. }
  2775. VFixNotebookDialog dialog(nb, notebooks, this);
  2776. if (dialog.exec()) {
  2777. qDebug() << "fix path of notebook" << nb->getName() << "to" << dialog.getPathInput();
  2778. nb->updatePath(dialog.getPathInput());
  2779. } else {
  2780. notebooks.removeOne(nb);
  2781. --i;
  2782. }
  2783. updated = true;
  2784. }
  2785. if (updated) {
  2786. g_config->setNotebooks(notebooks);
  2787. m_notebookSelector->update();
  2788. }
  2789. m_notebookSelector->restoreCurrentNotebook();
  2790. }
  2791. void VMainWindow::setMenuBarVisible(bool p_visible)
  2792. {
  2793. // Hiding the menubar will disable the shortcut of QActions.
  2794. if (p_visible) {
  2795. menuBar()->setFixedSize(QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX));
  2796. } else {
  2797. menuBar()->setFixedHeight(0);
  2798. }
  2799. }
  2800. void VMainWindow::setToolBarVisible(bool p_visible)
  2801. {
  2802. for (auto bar : m_toolBars) {
  2803. if (p_visible) {
  2804. bar->setFixedSize(QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX));
  2805. } else {
  2806. bar->setFixedHeight(0);
  2807. }
  2808. }
  2809. }
  2810. void VMainWindow::kickOffStartUpTimer(const QStringList &p_files)
  2811. {
  2812. QTimer::singleShot(300, [this, p_files]() {
  2813. checkNotebooks();
  2814. QCoreApplication::sendPostedEvents();
  2815. promptNewNotebookIfEmpty();
  2816. QCoreApplication::sendPostedEvents();
  2817. openStartupPages();
  2818. openFiles(p_files, false, g_config->getNoteOpenMode(), false, true);
  2819. if (g_config->versionChanged()) {
  2820. QString docFile = VUtils::getDocFile("welcome.md");
  2821. VFile *file = vnote->getFile(docFile, true);
  2822. m_editArea->openFile(file, OpenFileMode::Read);
  2823. }
  2824. });
  2825. }
  2826. void VMainWindow::showNotebookPanel()
  2827. {
  2828. changePanelView(PanelViewState::VerticalMode);
  2829. m_naviBox->setCurrentIndex(NaviBoxIndex::NotebookPanel, false);
  2830. }
  2831. void VMainWindow::showExplorerPanel(bool p_focus)
  2832. {
  2833. changePanelView(PanelViewState::VerticalMode);
  2834. m_naviBox->setCurrentIndex(NaviBoxIndex::Explorer, p_focus);
  2835. }
  2836. void VMainWindow::stayOnTop(bool p_enabled)
  2837. {
  2838. bool shown = isVisible();
  2839. Qt::WindowFlags flags = this->windowFlags();
  2840. Qt::WindowFlags magicFlag = Qt::WindowStaysOnTopHint;
  2841. if (p_enabled) {
  2842. setWindowFlags(flags | magicFlag);
  2843. } else {
  2844. setWindowFlags(flags ^ magicFlag);
  2845. }
  2846. if (shown) {
  2847. show();
  2848. }
  2849. }
  2850. void VMainWindow::focusEditArea() const
  2851. {
  2852. QWidget *widget = m_editArea->getCurrentTab();
  2853. if (!widget) {
  2854. widget = m_editArea;
  2855. }
  2856. widget->setFocus();
  2857. }
  2858. void VMainWindow::setCaptainModeEnabled(bool p_enabled)
  2859. {
  2860. m_captain->setCaptainModeEnabled(p_enabled);
  2861. }
  2862. void VMainWindow::initUpdateTimer()
  2863. {
  2864. m_updateTimer = new QTimer(this);
  2865. m_updateTimer->setSingleShot(true);
  2866. m_updateTimer->setInterval(200);
  2867. connect(m_updateTimer, &QTimer::timeout,
  2868. this, [this]() {
  2869. m_fileToolBar->update();
  2870. m_viewToolBar->update();
  2871. m_editToolBar->update();
  2872. m_noteToolBar->update();
  2873. });
  2874. }
  2875. void VMainWindow::restartVNote()
  2876. {
  2877. QCoreApplication::exit(RESTART_EXIT_CODE);
  2878. }
  2879. void VMainWindow::updateFontOfAllTabs()
  2880. {
  2881. QVector<VEditTab *> tabs = m_editArea->getAllTabs();
  2882. for (auto tab : tabs) {
  2883. const VMdTab *mdTab = dynamic_cast<const VMdTab *>(tab);
  2884. if (mdTab && mdTab->getEditor()) {
  2885. mdTab->getEditor()->updateFontAndPalette();
  2886. }
  2887. }
  2888. }