| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686 |
- #include "mainwindow.h"
- #include <QFileInfo>
- #include <QDebug>
- #include <QResizeEvent>
- #include <QSplitter>
- #include <QVariant>
- #include <QDockWidget>
- #include <QTextEdit>
- #include <QStatusBar>
- #include <QCloseEvent>
- #include <QVBoxLayout>
- #include <QTabBar>
- #include <QVariant>
- #include <QCoreApplication>
- #include <QApplication>
- #include <QShortcut>
- #include <QSystemTrayIcon>
- #include <QWindowStateChangeEvent>
- #include <QTimer>
- #include "toolbox.h"
- #include "notebookexplorer.h"
- #include "vnotex.h"
- #include "notebookmgr.h"
- #include "buffermgr.h"
- #include "viewarea.h"
- #include <core/configmgr.h>
- #include <core/sessionconfig.h>
- #include <core/coreconfig.h>
- #include <core/events.h>
- #include <core/fileopenparameters.h>
- #include <widgets/dialogs/exportdialog.h>
- #include "viewwindow.h"
- #include "outlineviewer.h"
- #include <utils/widgetutils.h>
- #include "navigationmodemgr.h"
- #include "messageboxhelper.h"
- #include "systemtrayhelper.h"
- #include "titletoolbar.h"
- using namespace vnotex;
- MainWindow::MainWindow(QWidget *p_parent)
- : QMainWindow(p_parent)
- {
- VNoteX::getInst().setMainWindow(this);
- NavigationModeMgr::init(this);
- setupUI();
- setupShortcuts();
- loadStateAndGeometry();
- // The signal is particularly useful if your application has to do some last-second cleanup.
- // Note that no user interaction is possible in this state.
- connect(qApp, &QCoreApplication::aboutToQuit,
- this, &MainWindow::closeOnQuit);
- connect(&VNoteX::getInst(), &VNoteX::exportRequested,
- this, &MainWindow::exportNotes);
- }
- MainWindow::~MainWindow()
- {
- // Should be desturcted before status bar.
- delete m_viewArea;
- m_viewArea = nullptr;
- }
- void MainWindow::kickOffOnStart(const QStringList &p_paths)
- {
- QTimer::singleShot(300, [this, p_paths]() {
- VNoteX::getInst().initLoad();
- emit mainWindowStarted();
- emit layoutChanged();
- demoWidget();
- openFiles(p_paths);
- });
- }
- void MainWindow::openFiles(const QStringList &p_files)
- {
- for (const auto &file : p_files) {
- emit VNoteX::getInst().openFileRequested(file, QSharedPointer<FileOpenParameters>::create());
- }
- }
- void MainWindow::setupUI()
- {
- setupCentralWidget();
- setupDocks();
- setupToolBar();
- setupStatusBar();
- setupTipsArea();
- setupSystemTray();
- activateDock(m_docks[DockIndex::NavigationDock]);
- }
- void MainWindow::setupStatusBar()
- {
- m_statusBarHelper.setupStatusBar(this);
- connect(&VNoteX::getInst(), &VNoteX::statusMessageRequested,
- statusBar(), &QStatusBar::showMessage);
- }
- void MainWindow::setupTipsArea()
- {
- connect(&VNoteX::getInst(), &VNoteX::tipsRequested,
- this, &MainWindow::showTips);
- }
- void MainWindow::createTipsArea()
- {
- if (m_tipsLabel) {
- return;
- }
- m_tipsLabel = new QLabel(this);
- m_tipsLabel->setObjectName("MainWindowTipsLabel");
- m_tipsLabel->hide();
- m_tipsTimer = new QTimer(this);
- m_tipsTimer->setSingleShot(true);
- m_tipsTimer->setInterval(3000);
- connect(m_tipsTimer, &QTimer::timeout,
- this, [this]() {
- setTipsAreaVisible(false);
- });
- }
- void MainWindow::setupCentralWidget()
- {
- m_viewArea = new ViewArea(this);
- NavigationModeMgr::getInst().registerNavigationTarget(m_viewArea);
- connect(&VNoteX::getInst().getBufferMgr(), &BufferMgr::bufferRequested,
- m_viewArea, &ViewArea::openBuffer);
- connect(m_viewArea, &ViewArea::statusWidgetChanged,
- this, [this](QWidget *p_widget) {
- if (m_viewAreaStatusWidget) {
- // Will hide it.
- statusBar()->removeWidget(m_viewAreaStatusWidget);
- }
- m_viewAreaStatusWidget = p_widget;
- if (m_viewAreaStatusWidget) {
- statusBar()->addPermanentWidget(m_viewAreaStatusWidget);
- m_viewAreaStatusWidget->show();
- }
- });
- connect(m_viewArea, &ViewArea::currentViewWindowChanged,
- this, [this]() {
- setWindowTitle(getViewAreaTitle());
- });
- connect(m_viewArea, &ViewArea::currentViewWindowUpdated,
- this, [this]() {
- setWindowTitle(getViewAreaTitle());
- });
- {
- auto notebookMgr = &VNoteX::getInst().getNotebookMgr();
- connect(notebookMgr, &NotebookMgr::notebookAboutToClose,
- this, [this](const Notebook *p_notebook) {
- m_viewArea->close(p_notebook, true);
- });
- connect(notebookMgr, &NotebookMgr::notebookAboutToRemove,
- this, [this](const Notebook *p_notebook) {
- m_viewArea->close(p_notebook, true);
- });
- }
- setCentralWidget(m_viewArea);
- }
- void MainWindow::setupDocks()
- {
- setTabPosition(Qt::LeftDockWidgetArea, QTabWidget::West);
- setTabPosition(Qt::RightDockWidgetArea, QTabWidget::East);
- setTabPosition(Qt::TopDockWidgetArea, QTabWidget::North);
- setTabPosition(Qt::BottomDockWidgetArea, QTabWidget::North);
- setDockNestingEnabled(true);
- // The order of m_docks should be identical with enum DockIndex.
- setupNavigationDock();
- setupOutlineDock();
- for (int i = 1; i < m_docks.size(); ++i) {
- tabifyDockWidget(m_docks[i - 1], m_docks[i]);
- }
- for (auto dock : m_docks) {
- connect(dock, &QDockWidget::visibilityChanged,
- this, [this]() {
- updateTabBarStyle();
- emit layoutChanged();
- });
- }
- // Activate the first dock.
- activateDock(m_docks[0]);
- }
- void MainWindow::activateDock(QDockWidget *p_dock)
- {
- p_dock->show();
- Q_FOREACH(QTabBar* tabBar, this->findChildren<QTabBar*>(QString(), Qt::FindDirectChildrenOnly)) {
- bool found = false;
- for (int i = 0; i < tabBar->count(); ++i) {
- if (p_dock == reinterpret_cast<QWidget *>(tabBar->tabData(i).toULongLong())) {
- tabBar->setCurrentIndex(i);
- found = true;
- break;
- }
- }
- if (found) {
- break;
- }
- }
- p_dock->setFocus();
- }
- void MainWindow::setupNavigationDock()
- {
- auto dock = new QDockWidget(tr("Navigation"), this);
- m_docks.push_back(dock);
- dock->setObjectName(QStringLiteral("NavigationDock.vnotex"));
- dock->setAllowedAreas(Qt::AllDockWidgetAreas);
- setupNavigationToolBox();
- dock->setWidget(m_navigationToolBox);
- dock->setFocusProxy(m_navigationToolBox);
- addDockWidget(Qt::LeftDockWidgetArea, dock);
- }
- void MainWindow::setupOutlineDock()
- {
- auto dock = new QDockWidget(tr("Outline"), this);
- m_docks.push_back(dock);
- dock->setObjectName(QStringLiteral("OutlineDock.vnotex"));
- dock->setAllowedAreas(Qt::AllDockWidgetAreas);
- setupOutlineViewer();
- dock->setWidget(m_outlineViewer);
- dock->setFocusProxy(m_outlineViewer);
- addDockWidget(Qt::LeftDockWidgetArea, dock);
- }
- void MainWindow::setupNavigationToolBox()
- {
- m_navigationToolBox = new ToolBox(this);
- m_navigationToolBox->setObjectName("NavigationToolBox.vnotex");
- NavigationModeMgr::getInst().registerNavigationTarget(m_navigationToolBox);
- const auto &themeMgr = VNoteX::getInst().getThemeMgr();
- // Notebook explorer.
- setupNotebookExplorer(m_navigationToolBox);
- m_navigationToolBox->addItem(m_notebookExplorer,
- themeMgr.getIconFile("notebook_explorer.svg"),
- tr("Notebooks"),
- nullptr);
- /*
- // History explorer.
- auto historyExplorer = new QWidget(this);
- m_navigationToolBox->addItem(historyExplorer,
- themeMgr.getIconFile("history_explorer.svg"),
- tr("History"),
- nullptr);
- // Tag explorer.
- auto tagExplorer = new QWidget(this);
- m_navigationToolBox->addItem(tagExplorer,
- themeMgr.getIconFile("tag_explorer.svg"),
- tr("Tags"),
- nullptr);
- */
- }
- void MainWindow::setupNotebookExplorer(QWidget *p_parent)
- {
- m_notebookExplorer = new NotebookExplorer(p_parent);
- connect(&VNoteX::getInst(), &VNoteX::newNotebookRequested,
- m_notebookExplorer, &NotebookExplorer::newNotebook);
- connect(&VNoteX::getInst(), &VNoteX::newNotebookFromFolderRequested,
- m_notebookExplorer, &NotebookExplorer::newNotebookFromFolder);
- connect(&VNoteX::getInst(), &VNoteX::importNotebookRequested,
- m_notebookExplorer, &NotebookExplorer::importNotebook);
- connect(&VNoteX::getInst(), &VNoteX::newFolderRequested,
- m_notebookExplorer, &NotebookExplorer::newFolder);
- connect(&VNoteX::getInst(), &VNoteX::newNoteRequested,
- m_notebookExplorer, &NotebookExplorer::newNote);
- connect(&VNoteX::getInst(), &VNoteX::importFileRequested,
- m_notebookExplorer, &NotebookExplorer::importFile);
- connect(&VNoteX::getInst(), &VNoteX::importFolderRequested,
- m_notebookExplorer, &NotebookExplorer::importFolder);
- connect(&VNoteX::getInst(), &VNoteX::importLegacyNotebookRequested,
- m_notebookExplorer, &NotebookExplorer::importLegacyNotebook);
- connect(&VNoteX::getInst(), &VNoteX::locateNodeRequested,
- m_notebookExplorer, &NotebookExplorer::locateNode);
- auto notebookMgr = &VNoteX::getInst().getNotebookMgr();
- connect(notebookMgr, &NotebookMgr::notebooksUpdated,
- m_notebookExplorer, &NotebookExplorer::loadNotebooks);
- connect(notebookMgr, &NotebookMgr::notebookUpdated,
- m_notebookExplorer, &NotebookExplorer::reloadNotebook);
- connect(notebookMgr, &NotebookMgr::currentNotebookChanged,
- m_notebookExplorer, &NotebookExplorer::setCurrentNotebook);
- connect(m_notebookExplorer, &NotebookExplorer::notebookActivated,
- notebookMgr, &NotebookMgr::setCurrentNotebook);
- }
- void MainWindow::closeEvent(QCloseEvent *p_event)
- {
- const int toTray = ConfigMgr::getInst().getSessionConfig().getMinimizeToSystemTray();
- bool isExit = m_requestQuit > -1 || toTray == 0;
- const int exitCode = m_requestQuit;
- m_requestQuit = -1;
- #if defined(Q_OS_MACOS)
- // Do not support minimized to tray on macOS.
- isExit = true;
- #endif
- bool needShowMessage = false;
- if(!isExit && toTray == -1){
- int ret = MessageBoxHelper::questionYesNo(MessageBoxHelper::Question,
- tr("Do you want to minimize %1 to system tray "
- "instead of quitting when closed?").arg(qApp->applicationName()),
- tr("You could change the option in Settings later."),
- QString(),
- this);
- if (ret == QMessageBox::Yes) {
- ConfigMgr::getInst().getSessionConfig().setMinimizeToSystemTray(true);
- needShowMessage = true;
- } else if (ret == QMessageBox::No) {
- ConfigMgr::getInst().getSessionConfig().setMinimizeToSystemTray(false);
- isExit = true;
- } else {
- p_event->ignore();
- return;
- }
- }
- if (isVisible()) {
- saveStateAndGeometry();
- }
- if (isExit || !m_trayIcon->isVisible()) {
- // Signal out the close event.
- auto event = QSharedPointer<Event>::create();
- event->m_response = true;
- emit mainWindowClosed(event);
- if (!event->m_response.toBool()) {
- // Stop the close.
- p_event->ignore();
- return;
- }
- QMainWindow::closeEvent(p_event);
- qApp->exit(exitCode > -1 ? exitCode : 0);
- } else {
- hide();
- p_event->ignore();
- if (needShowMessage) {
- m_trayIcon->showMessage(ConfigMgr::c_appName, tr("%1 is still running here.").arg(ConfigMgr::c_appName));
- }
- }
- }
- void MainWindow::saveStateAndGeometry()
- {
- if (m_layoutReset) {
- return;
- }
- SessionConfig::MainWindowStateGeometry sg;
- sg.m_mainState = saveState();
- sg.m_mainGeometry = saveGeometry();
- auto& sessionConfig = ConfigMgr::getInst().getSessionConfig();
- sessionConfig.setMainWindowStateGeometry(sg);
- }
- void MainWindow::loadStateAndGeometry()
- {
- const auto& sessionConfig = ConfigMgr::getInst().getSessionConfig();
- const auto sg = sessionConfig.getMainWindowStateGeometry();
- if (!sg.m_mainGeometry.isEmpty()) {
- restoreGeometry(sg.m_mainGeometry);
- }
- if (!sg.m_mainState.isEmpty()) {
- // Will also restore the state of dock widgets.
- restoreState(sg.m_mainState);
- }
- }
- void MainWindow::resetStateAndGeometry()
- {
- if (m_layoutReset) {
- return;
- }
- m_layoutReset = true;
- SessionConfig::MainWindowStateGeometry sg;
- auto& sessionConfig = ConfigMgr::getInst().getSessionConfig();
- sessionConfig.setMainWindowStateGeometry(sg);
- }
- void MainWindow::setContentAreaExpanded(bool p_expanded)
- {
- for (auto dock : m_docks) {
- if (!dock->isFloating()) {
- dock->setVisible(!p_expanded);
- }
- }
- }
- bool MainWindow::isContentAreaExpanded() const
- {
- for (auto dock : m_docks) {
- if (!dock->isFloating() && dock->isVisible()) {
- return false;
- }
- }
- return true;
- }
- void MainWindow::demoWidget()
- {
- }
- QString MainWindow::getViewAreaTitle() const
- {
- QString title;
- const auto win = m_viewArea->getCurrentViewWindow();
- if (win) {
- title = win->getName();
- }
- return title.isEmpty() ? QString() : QString("%1 - %2").arg(title, ConfigMgr::c_appName);
- }
- void MainWindow::setupOutlineViewer()
- {
- // Do not provide title here since there is one in the dock title.
- m_outlineViewer = new OutlineViewer(QString(), this);
- m_outlineViewer->setObjectName("OutlineViewer.vnotex");
- NavigationModeMgr::getInst().registerNavigationTarget(m_outlineViewer->getNavigationModeWrapper());
- connect(m_viewArea, &ViewArea::currentViewWindowChanged,
- this, [this]() {
- auto win = m_viewArea->getCurrentViewWindow();
- m_outlineViewer->setOutlineProvider(win ? win->getOutlineProvider() : nullptr);
- });
- connect(m_outlineViewer, &OutlineViewer::focusViewArea,
- this, &MainWindow::focusViewArea);
- }
- const QVector<QDockWidget *> &MainWindow::getDocks() const
- {
- return m_docks;
- }
- void MainWindow::focusViewArea()
- {
- m_viewArea->focus();
- }
- void MainWindow::setupToolBar()
- {
- const int sz = ConfigMgr::getInst().getCoreConfig().getToolBarIconSize();
- const QSize iconSize(sz, sz);
- if (!ConfigMgr::getInst().getSessionConfig().getSystemTitleBarEnabled()) {
- // Use unified tool bar as title bar.
- auto framelessFlags = Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowMinMaxButtonsHint
- | Qt::WindowCloseButtonHint | Qt::WindowFullscreenButtonHint;
- auto winFlags = windowFlags();
- winFlags |= Qt::CustomizeWindowHint;
- winFlags &= ~framelessFlags;
- setWindowFlags(winFlags);
- auto toolBar = new TitleToolBar(tr("Global"), this);
- toolBar->setIconSize(iconSize);
- m_toolBarHelper.setupToolBars(this, toolBar);
- toolBar->addTitleBarIcons(ToolBarHelper::generateIcon(QStringLiteral("minimize.svg")),
- ToolBarHelper::generateIcon(QStringLiteral("maximize.svg")),
- ToolBarHelper::generateIcon(QStringLiteral("maximize_restore.svg")),
- ToolBarHelper::generateDangerousIcon(QStringLiteral("close.svg")));
- } else {
- auto toolBar = new QToolBar(tr("Global"), this);
- toolBar->setIconSize(iconSize);
- m_toolBarHelper.setupToolBars(this, toolBar);
- }
- // Disable the context menu above tool bar.
- setContextMenuPolicy(Qt::NoContextMenu);
- }
- void MainWindow::closeOnQuit()
- {
- // No user interaction is available.
- emit mainWindowClosedOnQuit();
- }
- void MainWindow::setupShortcuts()
- {
- const auto &coreConfig = ConfigMgr::getInst().getCoreConfig();
- // Focus Navigation dock.
- {
- auto keys = coreConfig.getShortcut(CoreConfig::Shortcut::NavigationDock);
- auto shortcut = WidgetUtils::createShortcut(keys, this);
- if (shortcut) {
- auto dock = m_docks[DockIndex::NavigationDock];
- dock->setToolTip(QString("%1\t%2").arg(dock->windowTitle(),
- QKeySequence(keys).toString(QKeySequence::NativeText)));
- connect(shortcut, &QShortcut::activated,
- this, [this]() {
- activateDock(m_docks[DockIndex::NavigationDock]);
- });
- }
- }
- // Focus Outline dock.
- {
- auto keys = coreConfig.getShortcut(CoreConfig::Shortcut::OutlineDock);
- auto shortcut = WidgetUtils::createShortcut(keys, this);
- if (shortcut) {
- auto dock = m_docks[DockIndex::OutlineDock];
- dock->setToolTip(QString("%1\t%2").arg(dock->windowTitle(),
- QKeySequence(keys).toString(QKeySequence::NativeText)));
- connect(shortcut, &QShortcut::activated,
- this, [this]() {
- activateDock(m_docks[DockIndex::OutlineDock]);
- });
- }
- }
- }
- void MainWindow::setStayOnTop(bool p_enabled)
- {
- bool shown = isVisible();
- Qt::WindowFlags flags = windowFlags();
- const Qt::WindowFlags magicFlag = Qt::WindowStaysOnTopHint;
- if (p_enabled) {
- setWindowFlags(flags | magicFlag);
- } else {
- setWindowFlags(flags ^ magicFlag);
- }
- if (shown) {
- show();
- }
- }
- void MainWindow::setupSystemTray()
- {
- m_trayIcon = SystemTrayHelper::setupSystemTray(this);
- m_trayIcon->show();
- }
- void MainWindow::restart()
- {
- m_requestQuit = RESTART_EXIT_CODE;
- close();
- }
- void MainWindow::changeEvent(QEvent *p_event)
- {
- if (p_event->type() == QEvent::WindowStateChange) {
- QWindowStateChangeEvent *eve = static_cast<QWindowStateChangeEvent *>(p_event);
- m_windowOldState = eve->oldState();
- }
- QMainWindow::changeEvent(p_event);
- }
- void MainWindow::showMainWindow()
- {
- if (isMinimized()) {
- if (m_windowOldState & Qt::WindowMaximized) {
- showMaximized();
- } else if (m_windowOldState & Qt::WindowFullScreen) {
- showFullScreen();
- } else {
- showNormal();
- }
- } else {
- show();
- // Need to call raise() in macOS.
- raise();
- }
- activateWindow();
- }
- void MainWindow::quitApp()
- {
- m_requestQuit = 0;
- close();
- }
- void MainWindow::updateTabBarStyle()
- {
- Q_FOREACH(QTabBar* tabBar, this->findChildren<QTabBar*>(QString(), Qt::FindDirectChildrenOnly)) {
- tabBar->setDrawBase(false);
- }
- }
- void MainWindow::exportNotes()
- {
- auto currentNotebook = m_notebookExplorer->currentNotebook().data();
- auto viewWindow = m_viewArea->getCurrentViewWindow();
- auto folderNode = m_notebookExplorer->currentExploredFolderNode();
- if (folderNode && (folderNode->isRoot() || currentNotebook->isRecycleBinNode(folderNode))) {
- folderNode = nullptr;
- }
- auto noteNode = m_notebookExplorer->currentExploredNode();
- if (noteNode && !noteNode->hasContent()) {
- noteNode = nullptr;
- }
- ExportDialog dialog(currentNotebook,
- folderNode,
- noteNode,
- viewWindow ? viewWindow->getBuffer() : nullptr,
- this);
- dialog.exec();
- }
- void MainWindow::showTips(const QString &p_message, int p_timeoutMilliseconds)
- {
- createTipsArea();
- m_tipsTimer->stop();
- setTipsAreaVisible(false);
- if (p_message.isEmpty()) {
- return;
- }
- m_tipsLabel->setText(p_message);
- setTipsAreaVisible(true);
- m_tipsTimer->start(p_timeoutMilliseconds);
- }
- void MainWindow::setTipsAreaVisible(bool p_visible)
- {
- Q_ASSERT(m_tipsLabel);
- if (p_visible) {
- m_tipsLabel->adjustSize();
- int labelW = m_tipsLabel->width();
- int labelH = m_tipsLabel->height();
- int x = (width() - labelW) / 2;
- int y = (height() - labelH) / 2;
- if (x < 0) {
- x = 0;
- }
- if (y < 0) {
- y = 0;
- }
- m_tipsLabel->move(x, y);
- m_tipsLabel->show();
- } else {
- m_tipsLabel->hide();
- }
- }
|