diff --git a/src/resources/icons/corner_menu.svg b/src/resources/icons/corner_menu.svg
new file mode 100644
index 00000000..edf92f3d
--- /dev/null
+++ b/src/resources/icons/corner_menu.svg
@@ -0,0 +1,11 @@
+
+
+
+
diff --git a/src/resources/icons/remove_split.svg b/src/resources/icons/remove_split.svg
new file mode 100644
index 00000000..42be227f
--- /dev/null
+++ b/src/resources/icons/remove_split.svg
@@ -0,0 +1,10 @@
+
+
+
+
diff --git a/src/resources/icons/split_window.svg b/src/resources/icons/split_window.svg
new file mode 100644
index 00000000..c68272da
--- /dev/null
+++ b/src/resources/icons/split_window.svg
@@ -0,0 +1,9 @@
+
+
+
+
diff --git a/src/src.pro b/src/src.pro
index ed1aac0e..3812fc37 100644
--- a/src/src.pro
+++ b/src/src.pro
@@ -21,7 +21,6 @@ SOURCES += main.cpp\
vconfigmanager.cpp \
vfilelist.cpp \
dialog/vnewfiledialog.cpp \
- vtabwidget.cpp \
vedit.cpp \
veditor.cpp \
vnotefile.cpp \
@@ -40,7 +39,9 @@ SOURCES += main.cpp\
veditoperations.cpp \
vmdeditoperations.cpp \
dialog/vinsertimagedialog.cpp \
- vdownloader.cpp
+ vdownloader.cpp \
+ veditarea.cpp \
+ veditwindow.cpp
HEADERS += vmainwindow.h \
vdirectorytree.h \
@@ -50,7 +51,6 @@ HEADERS += vmainwindow.h \
vconfigmanager.h \
vfilelist.h \
dialog/vnewfiledialog.h \
- vtabwidget.h \
vedit.h \
veditor.h \
vconstants.h \
@@ -71,7 +71,9 @@ HEADERS += vmainwindow.h \
veditoperations.h \
vmdeditoperations.h \
dialog/vinsertimagedialog.h \
- vdownloader.h
+ vdownloader.h \
+ veditarea.h \
+ veditwindow.h
RESOURCES += \
vnote.qrc
diff --git a/src/veditarea.cpp b/src/veditarea.cpp
new file mode 100644
index 00000000..01d53e04
--- /dev/null
+++ b/src/veditarea.cpp
@@ -0,0 +1,274 @@
+#include
+#include "veditarea.h"
+#include "veditwindow.h"
+#include "veditor.h"
+#include "vnote.h"
+#include "vconfigmanager.h"
+
+VEditArea::VEditArea(VNote *vnote, QWidget *parent)
+ : QWidget(parent), vnote(vnote), curWindowIndex(0)
+{
+ setupUI();
+}
+
+void VEditArea::setupUI()
+{
+ splitter = new QSplitter(this);
+
+ // Add a window
+ insertSplitWindow(0);
+ setCurrentWindow(0, true);
+
+ QHBoxLayout *mainLayout = new QHBoxLayout();
+ mainLayout->addWidget(splitter);
+
+ setLayout(mainLayout);
+}
+
+void VEditArea::insertSplitWindow(int idx)
+{
+ VEditWindow *win = new VEditWindow(vnote);
+ splitter->insertWidget(idx, win);
+ connect(win, &VEditWindow::tabStatusChanged,
+ this, &VEditArea::curTabStatusChanged);
+ connect(win, &VEditWindow::requestSplitWindow,
+ this, &VEditArea::handleSplitWindowRequest);
+ connect(win, &VEditWindow::requestRemoveSplit,
+ this, &VEditArea::handleRemoveSplitRequest);
+ connect(win, &VEditWindow::getFocused,
+ this, &VEditArea::handleWindowFocused);
+
+ int nrWin = splitter->count();
+ if (nrWin == 1) {
+ // Disable removing split
+ win->setRemoveSplitEnable(false);
+ } else {
+ // Enable removing split
+ for (int i = 0; i < nrWin; ++i) {
+ getWindow(i)->setRemoveSplitEnable(true);
+ }
+ }
+}
+
+void VEditArea::removeSplitWindow(VEditWindow *win)
+{
+ if (!win) {
+ return;
+ }
+ win->hide();
+ // Should be deleted later
+ win->deleteLater();
+
+ int nrWin = splitter->count();
+ if (nrWin == 2) {
+ // Disable removing split
+ getWindow(0)->setRemoveSplitEnable(false);
+ getWindow(1)->setRemoveSplitEnable(false);
+ } else {
+ // Enable removing split
+ for (int i = 0; i < nrWin; ++i) {
+ getWindow(i)->setRemoveSplitEnable(true);
+ }
+ }
+}
+
+// A given file can be opened in multiple split windows. A given file could be
+// opened at most in one tab inside a window.
+void VEditArea::openFile(QJsonObject fileJson)
+{
+ if (fileJson.isEmpty()) {
+ return;
+ }
+
+ QString notebook = fileJson["notebook"].toString();
+ QString relativePath = fileJson["relative_path"].toString();
+ int mode = OpenFileMode::Read;
+ if (fileJson.contains("mode")) {
+ mode = fileJson["mode"].toInt();
+ }
+
+ qDebug() << "open notebook" << notebook << "path" << relativePath << mode;
+
+ // Find if it has been opened already
+ int winIdx, tabIdx;
+ bool setFocus = false;
+ auto tabs = findTabsByFile(notebook, relativePath);
+ if (!tabs.empty()) {
+ // Current window first
+ winIdx = tabs[0].first;
+ tabIdx = tabs[0].second;
+ for (int i = 0; i < tabs.size(); ++i) {
+ if (tabs[i].first == curWindowIndex) {
+ winIdx = tabs[i].first;
+ tabIdx = tabs[i].second;
+ break;
+ }
+ }
+ setFocus = true;
+ goto out;
+ }
+
+ // Open it in current window
+ winIdx = curWindowIndex;
+ tabIdx = openFileInWindow(winIdx, notebook, relativePath, mode);
+
+out:
+ setCurrentTab(winIdx, tabIdx, setFocus);
+}
+
+QVector > VEditArea::findTabsByFile(const QString ¬ebook, const QString &relativePath)
+{
+ QVector > tabs;
+ int nrWin = splitter->count();
+ for (int winIdx = 0; winIdx < nrWin; ++winIdx) {
+ VEditWindow *win = getWindow(winIdx);
+ int tabIdx = win->findTabByFile(notebook, relativePath);
+ if (tabIdx != -1) {
+ QPair match;
+ match.first = winIdx;
+ match.second = tabIdx;
+ tabs.append(match);
+ }
+ }
+ return tabs;
+}
+
+int VEditArea::openFileInWindow(int windowIndex, const QString ¬ebook, const QString &relativePath,
+ int mode)
+{
+ Q_ASSERT(windowIndex < splitter->count());
+ VEditWindow *win = getWindow(windowIndex);
+ return win->openFile(notebook, relativePath, mode);
+}
+
+void VEditArea::setCurrentTab(int windowIndex, int tabIndex, bool setFocus)
+{
+ setCurrentWindow(windowIndex, setFocus);
+
+ VEditWindow *win = getWindow(windowIndex);
+ win->setCurrentIndex(tabIndex);
+}
+
+void VEditArea::setCurrentWindow(int windowIndex, bool setFocus)
+{
+ if (curWindowIndex == windowIndex) {
+ return;
+ }
+ qDebug() << "current window" << windowIndex;
+ curWindowIndex = windowIndex;
+ if (setFocus) {
+ getWindow(windowIndex)->focusWindow();
+ }
+
+ // Update tab status
+ QString notebook, relativePath;
+ bool editMode, modifiable;
+ getWindow(curWindowIndex)->getTabStatus(notebook, relativePath, editMode, modifiable);
+ emit curTabStatusChanged(notebook, relativePath, editMode, modifiable);
+}
+
+void VEditArea::closeFile(QJsonObject fileJson)
+{
+ if (fileJson.isEmpty()) {
+ return;
+ }
+ QString notebook = fileJson["notebook"].toString();
+ QString relativePath = fileJson["relative_path"].toString();
+
+ int nrWin = splitter->count();
+ for (int i = 0; i < nrWin; ++i) {
+ VEditWindow *win = getWindow(i);
+ win->closeFile(notebook, relativePath);
+ }
+}
+
+void VEditArea::editFile()
+{
+ VEditWindow *win = getWindow(curWindowIndex);
+ win->editFile();
+}
+
+void VEditArea::saveFile()
+{
+ VEditWindow *win = getWindow(curWindowIndex);
+ win->saveFile();
+}
+
+void VEditArea::readFile()
+{
+ VEditWindow *win = getWindow(curWindowIndex);
+ win->readFile();
+}
+
+void VEditArea::saveAndReadFile()
+{
+ VEditWindow *win = getWindow(curWindowIndex);
+ win->saveAndReadFile();
+}
+
+void VEditArea::handleNotebookRenamed(const QVector ¬ebooks,
+ const QString &oldName, const QString &newName)
+{
+ int nrWin = splitter->count();
+ for (int i = 0; i < nrWin; ++i) {
+ VEditWindow *win = getWindow(i);
+ win->handleNotebookRenamed(notebooks, oldName, newName);
+ }
+}
+
+void VEditArea::handleSplitWindowRequest(VEditWindow *curWindow)
+{
+ if (!curWindow) {
+ return;
+ }
+ int idx = splitter->indexOf(curWindow);
+ qDebug() << "window" << idx << "requests split itself";
+ insertSplitWindow(++idx);
+ setCurrentWindow(idx, true);
+}
+
+void VEditArea::handleRemoveSplitRequest(VEditWindow *curWindow)
+{
+ if (!curWindow) {
+ return;
+ }
+ int idx = splitter->indexOf(curWindow);
+
+ removeSplitWindow(curWindow);
+
+ if (idx >= splitter->count()) {
+ idx = splitter->count() - 1;
+ }
+
+ // At least one split window left
+ Q_ASSERT(idx >= 0);
+ setCurrentWindow(idx, true);
+}
+
+void VEditArea::mousePressEvent(QMouseEvent *event)
+{
+ return;
+ qDebug() << "VEditArea press event" << event;
+ QPoint pos = event->pos();
+ int nrWin = splitter->count();
+ for (int i = 0; i < nrWin; ++i) {
+ VEditWindow *win = getWindow(i);
+ if (win->geometry().contains(pos, true)) {
+ setCurrentWindow(i, true);
+ break;
+ }
+ }
+ QWidget::mousePressEvent(event);
+}
+
+void VEditArea::handleWindowFocused()
+{
+ QObject *winObject = sender();
+ int nrWin = splitter->count();
+ for (int i = 0; i < nrWin; ++i) {
+ if (splitter->widget(i) == winObject) {
+ setCurrentWindow(i, false);
+ break;
+ }
+ }
+}
diff --git a/src/veditarea.h b/src/veditarea.h
new file mode 100644
index 00000000..3c6cb6d2
--- /dev/null
+++ b/src/veditarea.h
@@ -0,0 +1,70 @@
+#ifndef VEDITAREA_H
+#define VEDITAREA_H
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "vnotebook.h"
+#include "veditwindow.h"
+
+class VNote;
+
+class VEditArea : public QWidget
+{
+ Q_OBJECT
+public:
+ explicit VEditArea(VNote *vnote, QWidget *parent = 0);
+
+signals:
+ void curTabStatusChanged(const QString ¬ebook, const QString &relativePath,
+ bool editMode, bool modifiable);
+
+protected:
+ void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
+
+public slots:
+ void openFile(QJsonObject fileJson);
+ // Close the file forcely
+ void closeFile(QJsonObject fileJson);
+ void editFile();
+ void saveFile();
+ void readFile();
+ void saveAndReadFile();
+ void handleNotebookRenamed(const QVector ¬ebooks, const QString &oldName,
+ const QString &newName);
+
+private slots:
+ void handleSplitWindowRequest(VEditWindow *curWindow);
+ void handleRemoveSplitRequest(VEditWindow *curWindow);
+ void handleWindowFocused();
+
+private:
+ void setupUI();
+ QVector > findTabsByFile(const QString ¬ebook, const QString &relativePath);
+ int openFileInWindow(int windowIndex, const QString ¬ebook, const QString &relativePath,
+ int mode);
+ void setCurrentTab(int windowIndex, int tabIndex, bool setFocus);
+ void setCurrentWindow(int windowIndex, bool setFocus);
+ inline VEditWindow *getWindow(int windowIndex) const;
+ void insertSplitWindow(int idx);
+ void removeSplitWindow(VEditWindow *win);
+
+ VNote *vnote;
+ int curWindowIndex;
+
+ // Splitter holding multiple split windows
+ QSplitter *splitter;
+};
+
+inline VEditWindow* VEditArea::getWindow(int windowIndex) const
+{
+ return dynamic_cast(splitter->widget(windowIndex));
+}
+
+#endif // VEDITAREA_H
diff --git a/src/veditor.cpp b/src/veditor.cpp
index e6754e20..9850b342 100644
--- a/src/veditor.cpp
+++ b/src/veditor.cpp
@@ -32,6 +32,9 @@ VEditor::VEditor(const QString &path, bool modifiable, QWidget *parent)
setupUI();
showFileReadMode();
+
+ connect(qApp, &QApplication::focusChanged,
+ this, &VEditor::handleFocusChanged);
}
VEditor::~VEditor()
@@ -148,7 +151,7 @@ void VEditor::readFile()
if (textEditor->isModified()) {
// Need to save the changes
QMessageBox msgBox(this);
- msgBox.setText("The note has been modified.");
+ msgBox.setText(QString("The note \"%1\" has been modified.").arg(noteFile->fileName));
msgBox.setInformativeText("Do you want to save your changes?");
msgBox.setIcon(QMessageBox::Information);
msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
@@ -220,3 +223,15 @@ void VEditor::setupMarkdownPreview()
addWidget(webPreviewer);
}
+
+void VEditor::focusTab()
+{
+ currentWidget()->setFocus();
+}
+
+void VEditor::handleFocusChanged(QWidget *old, QWidget *now)
+{
+ if (isChild(now)) {
+ emit getFocused();
+ }
+}
diff --git a/src/veditor.h b/src/veditor.h
index 45de4a13..f0bbd248 100644
--- a/src/veditor.h
+++ b/src/veditor.h
@@ -16,6 +16,7 @@ class VNote;
class VEditor : public QStackedWidget
{
+ Q_OBJECT
public:
VEditor(const QString &path, bool modifiable, QWidget *parent = 0);
~VEditor();
@@ -29,6 +30,13 @@ public:
inline bool getIsEditMode() const;
inline bool isModified() const;
+ void focusTab();
+
+signals:
+ void getFocused();
+
+private slots:
+ void handleFocusChanged(QWidget *old, QWidget *now);
private:
bool isMarkdown(const QString &name);
@@ -37,6 +45,7 @@ private:
void showFileEditMode();
void setupMarkdownPreview();
void previewByConverter();
+ inline bool isChild(QObject *obj);
VNoteFile *noteFile;
bool isEditMode;
@@ -57,4 +66,15 @@ inline bool VEditor::isModified() const
return textEditor->isModified();
}
+inline bool VEditor::isChild(QObject *obj)
+{
+ while (obj) {
+ if (obj == this) {
+ return true;
+ }
+ obj = obj->parent();
+ }
+ return false;
+}
+
#endif // VEDITOR_H
diff --git a/src/veditwindow.cpp b/src/veditwindow.cpp
new file mode 100644
index 00000000..e425dc02
--- /dev/null
+++ b/src/veditwindow.cpp
@@ -0,0 +1,296 @@
+#include
+#include
+#include "veditwindow.h"
+#include "veditor.h"
+#include "vnote.h"
+#include "vconfigmanager.h"
+
+extern VConfigManager vconfig;
+
+VEditWindow::VEditWindow(VNote *vnote, QWidget *parent)
+ : QTabWidget(parent), vnote(vnote)
+{
+ setupCornerWidget();
+
+ setTabsClosable(true);
+ setMovable(true);
+
+ connect(this, &VEditWindow::tabCloseRequested,
+ this, &VEditWindow::handleTabCloseRequest);
+ connect(this, &VEditWindow::tabBarClicked,
+ this, &VEditWindow::handleTabbarClicked);
+}
+
+void VEditWindow::setupCornerWidget()
+{
+ // Right corner button
+ // Actions
+ splitAct = new QAction(QIcon(":/resources/icons/split_window.svg"),
+ tr("Split"), this);
+ splitAct->setStatusTip(tr("Split current window vertically"));
+ connect(splitAct, &QAction::triggered,
+ this, &VEditWindow::splitWindow);
+
+ removeSplitAct = new QAction(QIcon(":/resources/icons/remove_split.svg"),
+ tr("Remove split"), this);
+ removeSplitAct->setStatusTip(tr("Remove current split window"));
+ connect(removeSplitAct, &QAction::triggered,
+ this, &VEditWindow::removeSplit);
+
+ rightBtn = new QPushButton(QIcon(":/resources/icons/corner_menu.svg"),
+ "", this);
+ QMenu *rightMenu = new QMenu(this);
+ rightMenu->addAction(splitAct);
+ rightMenu->addAction(removeSplitAct);
+ rightBtn->setMenu(rightMenu);
+
+ setCornerWidget(rightBtn, Qt::TopRightCorner);
+}
+
+void VEditWindow::splitWindow()
+{
+ emit requestSplitWindow(this);
+}
+
+void VEditWindow::removeSplit()
+{
+ // Close all the files one by one
+ // If user do not want to close a file, just stop removing
+ if (closeAllFiles()) {
+ Q_ASSERT(count() == 0);
+ emit requestRemoveSplit(this);
+ }
+}
+
+void VEditWindow::setRemoveSplitEnable(bool enabled)
+{
+ removeSplitAct->setVisible(enabled);
+}
+
+void VEditWindow::openWelcomePage()
+{
+ int idx = openFileInTab("", vconfig.getWelcomePagePath(), false);
+ setTabText(idx, "Welcome to VNote");
+ setTabToolTip(idx, "VNote");
+}
+
+int VEditWindow::insertTabWithData(int index, QWidget *page,
+ const QJsonObject &tabData)
+{
+ QString label = getFileName(tabData["relative_path"].toString());
+ int idx = insertTab(index, page, label);
+ QTabBar *tabs = tabBar();
+ tabs->setTabData(idx, tabData);
+ noticeTabStatus(currentIndex());
+ return idx;
+}
+
+int VEditWindow::appendTabWithData(QWidget *page, const QJsonObject &tabData)
+{
+ return insertTabWithData(count(), page, tabData);
+}
+
+int VEditWindow::openFile(const QString ¬ebook, const QString &relativePath, int mode)
+{
+ // Find if it has been opened already
+ int idx = findTabByFile(notebook, relativePath);
+ if (idx > -1) {
+ goto out;
+ }
+ idx = openFileInTab(notebook, relativePath, true);
+out:
+ setCurrentIndex(idx);
+ if (mode == OpenFileMode::Edit) {
+ editFile();
+ }
+ focusWindow();
+ return idx;
+}
+
+void VEditWindow::closeFile(const QString ¬ebook, const QString &relativePath)
+{
+ // Find if it has been opened already
+ int idx = findTabByFile(notebook, relativePath);
+ if (idx == -1) {
+ return;
+ }
+
+ // Do not check if modified
+ VEditor *editor = getTab(idx);
+ Q_ASSERT(editor);
+ removeTab(idx);
+ delete editor;
+}
+
+bool VEditWindow::closeAllFiles()
+{
+ int nrTab = count();
+ for (int i = 0; i < nrTab; ++i) {
+ // Always close the first tab
+ if (!handleTabCloseRequest(0)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+int VEditWindow::openFileInTab(const QString ¬ebook, const QString &relativePath,
+ bool modifiable)
+{
+ QString rootPath;
+ const QVector ¬ebooks = vnote->getNotebooks();
+ for (int i = 0; i < notebooks.size(); ++i) {
+ if (notebooks[i].getName() == notebook) {
+ rootPath = notebooks[i].getPath();
+ break;
+ }
+ }
+
+ VEditor *editor = new VEditor(QDir::cleanPath(QDir(rootPath).filePath(relativePath)),
+ modifiable);
+ connect(editor, &VEditor::getFocused,
+ this, &VEditWindow::getFocused);
+
+ QJsonObject tabJson;
+ tabJson["notebook"] = notebook;
+ tabJson["relative_path"] = relativePath;
+ tabJson["modifiable"] = modifiable;
+ return appendTabWithData(editor, tabJson);
+}
+
+int VEditWindow::findTabByFile(const QString ¬ebook, const QString &relativePath) const
+{
+ QTabBar *tabs = tabBar();
+ int nrTabs = tabs->count();
+
+ for (int i = 0; i < nrTabs; ++i) {
+ QJsonObject tabJson = tabs->tabData(i).toJsonObject();
+ if (tabJson["notebook"] == notebook && tabJson["relative_path"] == relativePath) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+bool VEditWindow::handleTabCloseRequest(int index)
+{
+ qDebug() << "request closing tab" << index;
+ VEditor *editor = getTab(index);
+ Q_ASSERT(editor);
+ bool ok = editor->requestClose();
+ if (ok) {
+ removeTab(index);
+ delete editor;
+ }
+ noticeTabStatus(currentIndex());
+ // User clicks the close button. We should make this window
+ // to be current window.
+ emit getFocused();
+ return ok;
+}
+
+void VEditWindow::readFile()
+{
+ VEditor *editor = getTab(currentIndex());
+ Q_ASSERT(editor);
+ editor->readFile();
+ noticeTabStatus(currentIndex());
+}
+
+void VEditWindow::saveAndReadFile()
+{
+ saveFile();
+ readFile();
+ noticeTabStatus(currentIndex());
+}
+
+void VEditWindow::editFile()
+{
+ VEditor *editor = getTab(currentIndex());
+ Q_ASSERT(editor);
+ editor->editFile();
+ noticeTabStatus(currentIndex());
+}
+
+void VEditWindow::saveFile()
+{
+ VEditor *editor = getTab(currentIndex());
+ Q_ASSERT(editor);
+ editor->saveFile();
+}
+
+void VEditWindow::handleNotebookRenamed(const QVector ¬ebooks,
+ const QString &oldName, const QString &newName)
+{
+ QTabBar *tabs = tabBar();
+ int nrTabs = tabs->count();
+ for (int i = 0; i < nrTabs; ++i) {
+ QJsonObject tabJson = tabs->tabData(i).toJsonObject();
+ if (tabJson["notebook"] == oldName) {
+ tabJson["notebook"] = newName;
+ tabs->setTabData(i, tabJson);
+ }
+ }
+}
+
+void VEditWindow::noticeTabStatus(int index)
+{
+ if (index == -1) {
+ emit tabStatusChanged("", "", false, false);
+ return;
+ }
+
+ QJsonObject tabJson = tabBar()->tabData(index).toJsonObject();
+ Q_ASSERT(!tabJson.isEmpty());
+
+ QString notebook = tabJson["notebook"].toString();
+ QString relativePath = tabJson["relative_path"].toString();
+ VEditor *editor = getTab(index);
+ bool editMode = editor->getIsEditMode();
+ bool modifiable = tabJson["modifiable"].toBool();
+
+ emit tabStatusChanged(notebook, relativePath,
+ editMode, modifiable);
+}
+
+void VEditWindow::getTabStatus(QString ¬ebook, QString &relativePath,
+ bool &editMode, bool &modifiable) const
+{
+ int idx = currentIndex();
+ if (idx == -1) {
+ notebook = relativePath = "";
+ editMode = modifiable = false;
+ return;
+ }
+
+ QJsonObject tabJson = tabBar()->tabData(idx).toJsonObject();
+ Q_ASSERT(!tabJson.isEmpty());
+ notebook = tabJson["notebook"].toString();
+ relativePath = tabJson["relative_path"].toString();
+ VEditor *editor = getTab(idx);
+ editMode = editor->getIsEditMode();
+ modifiable = tabJson["modifiable"].toBool();
+}
+
+void VEditWindow::focusWindow()
+{
+ int idx = currentIndex();
+ if (idx == -1) {
+ setFocus();
+ return;
+ }
+ getTab(idx)->focusTab();
+}
+
+void VEditWindow::handleTabbarClicked(int index)
+{
+ // The child will emit getFocused here
+ focusWindow();
+ noticeTabStatus(index);
+}
+
+void VEditWindow::mousePressEvent(QMouseEvent *event)
+{
+ emit getFocused();
+ QTabWidget::mousePressEvent(event);
+}
diff --git a/src/veditwindow.h b/src/veditwindow.h
new file mode 100644
index 00000000..e2e41680
--- /dev/null
+++ b/src/veditwindow.h
@@ -0,0 +1,84 @@
+#ifndef VEDITWINDOW_H
+#define VEDITWINDOW_H
+
+#include
+#include
+#include
+#include
+#include
+#include "vnotebook.h"
+#include "veditor.h"
+
+class VNote;
+class QPushButton;
+
+class VEditWindow : public QTabWidget
+{
+ Q_OBJECT
+public:
+ explicit VEditWindow(VNote *vnote, QWidget *parent = 0);
+ int findTabByFile(const QString ¬ebook, const QString &relativePath) const;
+ int openFile(const QString ¬ebook, const QString &relativePath,
+ int mode);
+ // Close the file forcely
+ void closeFile(const QString ¬ebook, const QString &relativePath);
+ void editFile();
+ void saveFile();
+ void readFile();
+ void saveAndReadFile();
+ void handleNotebookRenamed(const QVector ¬ebooks, const QString &oldName,
+ const QString &newName);
+ bool closeAllFiles();
+ void setRemoveSplitEnable(bool enabled);
+ void getTabStatus(QString ¬ebook, QString &relativePath,
+ bool &editMode, bool &modifiable) const;
+ // Focus to current tab's editor
+ void focusWindow();
+
+protected:
+ void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
+
+signals:
+ void tabStatusChanged(const QString ¬ebook, const QString &relativePath,
+ bool editMode, bool modifiable);
+ void requestSplitWindow(VEditWindow *curWindow);
+ void requestRemoveSplit(VEditWindow *curWindow);
+ // This widget or its children get the focus
+ void getFocused();
+
+private slots:
+ bool handleTabCloseRequest(int index);
+ void splitWindow();
+ void removeSplit();
+ void handleTabbarClicked(int index);
+
+private:
+ void setupCornerWidget();
+ void openWelcomePage();
+ int insertTabWithData(int index, QWidget *page, const QJsonObject &tabData);
+ int appendTabWithData(QWidget *page, const QJsonObject &tabData);
+ int openFileInTab(const QString ¬ebook, const QString &relativePath, bool modifiable);
+ inline QString getFileName(const QString &relativePath) const;
+ inline VEditor *getTab(int tabIndex) const;
+ void noticeTabStatus(int index);
+
+ VNote *vnote;
+ // Button in the right corner
+ QPushButton *rightBtn;
+
+ // Actions
+ QAction *splitAct;
+ QAction *removeSplitAct;
+};
+
+inline QString VEditWindow::getFileName(const QString &path) const
+{
+ return QFileInfo(QDir::cleanPath(path)).fileName();
+}
+
+inline VEditor* VEditWindow::getTab(int tabIndex) const
+{
+ return dynamic_cast(widget(tabIndex));
+}
+
+#endif // VEDITWINDOW_H
diff --git a/src/vmainwindow.cpp b/src/vmainwindow.cpp
index ec71eb81..9bd7746e 100644
--- a/src/vmainwindow.cpp
+++ b/src/vmainwindow.cpp
@@ -4,11 +4,11 @@
#include "vdirectorytree.h"
#include "vnote.h"
#include "vfilelist.h"
-#include "vtabwidget.h"
#include "vconfigmanager.h"
#include "dialog/vnewnotebookdialog.h"
#include "dialog/vnotebookinfodialog.h"
#include "utils/vutils.h"
+#include "veditarea.h"
extern VConfigManager vconfig;
@@ -79,15 +79,14 @@ void VMainWindow::setupUI()
fileList = new VFileList(vnote);
fileList->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Expanding);
- // Editor tab widget
- tabs = new VTabWidget(vnote);
- tabs->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+ editArea = new VEditArea(vnote);
+ editArea->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
// Main Splitter
mainSplitter = new QSplitter();
mainSplitter->addWidget(nbContainer);
mainSplitter->addWidget(fileList);
- mainSplitter->addWidget(tabs);
+ mainSplitter->addWidget(editArea);
mainSplitter->setStretchFactor(0, 0);
mainSplitter->setStretchFactor(1, 0);
mainSplitter->setStretchFactor(2, 1);
@@ -106,14 +105,14 @@ void VMainWindow::setupUI()
this, &VMainWindow::handleFileListDirectoryChanged);
connect(fileList, &VFileList::fileClicked,
- tabs, &VTabWidget::openFile);
+ editArea, &VEditArea::openFile);
connect(fileList, &VFileList::fileDeleted,
- tabs, &VTabWidget::closeFile);
+ editArea, &VEditArea::closeFile);
connect(fileList, &VFileList::fileCreated,
- tabs, &VTabWidget::openFile);
+ editArea, &VEditArea::openFile);
connect(vnote, &VNote::notebooksRenamed,
- tabs, &VTabWidget::handleNotebookRenamed);
- connect(tabs, &VTabWidget::tabModeChanged,
+ editArea, &VEditArea::handleNotebookRenamed);
+ connect(editArea, &VEditArea::curTabStatusChanged,
this, &VMainWindow::updateToolbarFromTabChage);
connect(newNotebookBtn, &QPushButton::clicked,
@@ -160,26 +159,26 @@ void VMainWindow::initActions()
tr("&Edit"), this);
editNoteAct->setStatusTip(tr("Edit current note"));
connect(editNoteAct, &QAction::triggered,
- tabs, &VTabWidget::editFile);
+ editArea, &VEditArea::editFile);
discardExitAct = new QAction(QIcon(":/resources/icons/discard_exit.svg"),
tr("Discard changes and exit"), this);
discardExitAct->setStatusTip(tr("Discard changes and exit edit mode"));
connect(discardExitAct, &QAction::triggered,
- tabs, &VTabWidget::readFile);
+ editArea, &VEditArea::readFile);
saveExitAct = new QAction(QIcon(":/resources/icons/save_exit.svg"),
tr("Save changes and exit"), this);
saveExitAct->setStatusTip(tr("Save changes and exit edit mode"));
connect(saveExitAct, &QAction::triggered,
- tabs, &VTabWidget::saveAndReadFile);
+ editArea, &VEditArea::saveAndReadFile);
saveNoteAct = new QAction(QIcon(":/resources/icons/save_note.svg"),
tr("&Save"), this);
saveNoteAct->setStatusTip(tr("Save current note"));
saveNoteAct->setShortcut(QKeySequence::Save);
connect(saveNoteAct, &QAction::triggered,
- tabs, &VTabWidget::saveFile);
+ editArea, &VEditArea::saveFile);
viewAct = new QActionGroup(this);
twoPanelViewAct = new QAction(QIcon(":/resources/icons/two_panels.svg"),
diff --git a/src/vmainwindow.h b/src/vmainwindow.h
index e1a8b1a0..977f754d 100644
--- a/src/vmainwindow.h
+++ b/src/vmainwindow.h
@@ -11,12 +11,12 @@ class QListWidget;
class QTabWidget;
class QToolBar;
class VNote;
-class VTabWidget;
class QAction;
class QPushButton;
class VNotebook;
class QActionGroup;
class VFileList;
+class VEditArea;
class VMainWindow : public QMainWindow
{
@@ -65,6 +65,7 @@ private:
// If true, comboBox changes will not trigger any signal out
bool notebookComboMuted;
+ VNote *vnote;
QLabel *notebookLabel;
QLabel *directoryLabel;
@@ -77,9 +78,8 @@ private:
QPushButton *dirInfoBtn;
VFileList *fileList;
VDirectoryTree *directoryTree;
- VTabWidget *tabs;
QSplitter *mainSplitter;
- VNote *vnote;
+ VEditArea *editArea;
// Actions
QAction *newNoteAct;
diff --git a/src/vnote.qrc b/src/vnote.qrc
index 6dd624de..4a40ded6 100644
--- a/src/vnote.qrc
+++ b/src/vnote.qrc
@@ -53,5 +53,8 @@
resources/icons/expand.svg
resources/icons/two_panels.svg
resources/icons/one_panel.svg
+ resources/icons/split_window.svg
+ resources/icons/corner_menu.svg
+ resources/icons/remove_split.svg
diff --git a/src/vtabwidget.cpp b/src/vtabwidget.cpp
deleted file mode 100644
index a655ab64..00000000
--- a/src/vtabwidget.cpp
+++ /dev/null
@@ -1,210 +0,0 @@
-#include
-#include
-#include "vtabwidget.h"
-#include "veditor.h"
-#include "vnote.h"
-#include "vconfigmanager.h"
-
-extern VConfigManager vconfig;
-
-VTabWidget::VTabWidget(VNote *vnote, QWidget *parent)
- : QTabWidget(parent), vnote(vnote)
-{
- setTabsClosable(true);
- setMovable(true);
- connect(this, &VTabWidget::tabCloseRequested,
- this, &VTabWidget::handleTabCloseRequest);
- connect(this, &VTabWidget::currentChanged,
- this, &VTabWidget::onCurrentChanged);
-}
-
-void VTabWidget::openWelcomePage()
-{
- int idx = openFileInTab("", vconfig.getWelcomePagePath(), false);
- setTabText(idx, "Welcome to VNote");
- setTabToolTip(idx, "VNote");
-}
-
-int VTabWidget::insertTabWithData(int index, QWidget *page,
- const QJsonObject &tabData)
-{
- QString label = getFileName(tabData["relative_path"].toString());
- int idx = insertTab(index, page, label);
- QTabBar *tabs = tabBar();
- tabs->setTabData(idx, tabData);
-
- // Need to update again with tabData
- onCurrentChanged(idx);
- return idx;
-}
-
-int VTabWidget::appendTabWithData(QWidget *page, const QJsonObject &tabData)
-{
- return insertTabWithData(count(), page, tabData);
-}
-
-void VTabWidget::openFile(QJsonObject fileJson)
-{
- if (fileJson.isEmpty()) {
- return;
- }
-
- QString notebook = fileJson["notebook"].toString();
- QString relativePath = fileJson["relative_path"].toString();
- int mode = OpenFileMode::Read;
- if (fileJson.contains("mode")) {
- mode = fileJson["mode"].toInt();
- }
-
- qDebug() << "open notebook" << notebook << "path" << relativePath << mode;
-
- // Find if it has been opened already
- int idx = findTabByFile(notebook, relativePath);
- if (idx > -1) {
- goto out;
- }
-
- idx = openFileInTab(notebook, relativePath, true);
-
-out:
- setCurrentIndex(idx);
- if (mode == OpenFileMode::Edit) {
- editFile();
- }
-}
-
-void VTabWidget::closeFile(QJsonObject fileJson)
-{
- if (fileJson.isEmpty()) {
- return;
- }
- qDebug() << "close file:" << fileJson;
-
- QString notebook = fileJson["notebook"].toString();
- QString relativePath = fileJson["relative_path"].toString();
-
- // Find if it has been opened already
- int idx = findTabByFile(notebook, relativePath);
- if (idx == -1) {
- return;
- }
-
- QWidget* page = widget(idx);
- Q_ASSERT(page);
- removeTab(idx);
- delete page;
-}
-
-int VTabWidget::openFileInTab(const QString ¬ebook, const QString &relativePath,
- bool modifiable)
-{
- QString rootPath;
- const QVector ¬ebooks = vnote->getNotebooks();
- for (int i = 0; i < notebooks.size(); ++i) {
- if (notebooks[i].getName() == notebook) {
- rootPath = notebooks[i].getPath();
- break;
- }
- }
-
- VEditor *editor = new VEditor(QDir::cleanPath(QDir(rootPath).filePath(relativePath)),
- modifiable);
- QJsonObject tabJson;
- tabJson["notebook"] = notebook;
- tabJson["relative_path"] = relativePath;
- tabJson["modifiable"] = modifiable;
- return appendTabWithData(editor, tabJson);
-}
-
-int VTabWidget::findTabByFile(const QString ¬ebook, const QString &relativePath) const
-{
- QTabBar *tabs = tabBar();
- int nrTabs = tabs->count();
-
- for (int i = 0; i < nrTabs; ++i) {
- QJsonObject tabJson = tabs->tabData(i).toJsonObject();
- if (tabJson["notebook"] == notebook && tabJson["relative_path"] == relativePath) {
- return i;
- }
- }
- return -1;
-}
-
-void VTabWidget::handleTabCloseRequest(int index)
-{
- qDebug() << "request closing tab" << index;
- VEditor *editor = dynamic_cast(widget(index));
- Q_ASSERT(editor);
- bool ok = editor->requestClose();
- if (ok) {
- removeTab(index);
- delete editor;
- }
-}
-
-void VTabWidget::readFile()
-{
- VEditor *editor = dynamic_cast(currentWidget());
- Q_ASSERT(editor);
- editor->readFile();
- onCurrentChanged(currentIndex());
-}
-
-void VTabWidget::saveAndReadFile()
-{
- saveFile();
- readFile();
- onCurrentChanged(currentIndex());
-}
-
-void VTabWidget::editFile()
-{
- VEditor *editor = dynamic_cast(currentWidget());
- Q_ASSERT(editor);
- editor->editFile();
- onCurrentChanged(currentIndex());
-}
-
-void VTabWidget::saveFile()
-{
- VEditor *editor = dynamic_cast(currentWidget());
- Q_ASSERT(editor);
- editor->saveFile();
-}
-
-void VTabWidget::handleNotebookRenamed(const QVector ¬ebooks,
- const QString &oldName, const QString &newName)
-{
- QTabBar *tabs = tabBar();
- int nrTabs = tabs->count();
- for (int i = 0; i < nrTabs; ++i) {
- QJsonObject tabJson = tabs->tabData(i).toJsonObject();
- if (tabJson["notebook"] == oldName) {
- tabJson["notebook"] = newName;
- tabs->setTabData(i, tabJson);
- }
- }
-}
-
-void VTabWidget::onCurrentChanged(int index)
-{
- if (index == -1) {
- emit tabModeChanged("", "", false, false);
- return;
- }
-
- QJsonObject tabJson = tabBar()->tabData(index).toJsonObject();
- if (tabJson.isEmpty()) {
- // Maybe the tab data has not been set yet
- return;
- }
-
- QString notebook = tabJson["notebook"].toString();
- QString relativePath = tabJson["relative_path"].toString();
- VEditor *editor = (VEditor *)widget(index);
- bool editMode = editor->getIsEditMode();
- bool modifiable = tabJson["modifiable"].toBool();
-
- emit tabModeChanged(notebook, relativePath,
- editMode, modifiable);
-}
diff --git a/src/vtabwidget.h b/src/vtabwidget.h
deleted file mode 100644
index e082228a..00000000
--- a/src/vtabwidget.h
+++ /dev/null
@@ -1,54 +0,0 @@
-#ifndef VTABWIDGET_H
-#define VTABWIDGET_H
-
-#include
-#include
-#include
-#include
-#include
-#include "vnotebook.h"
-
-class VNote;
-
-class VTabWidget : public QTabWidget
-{
- Q_OBJECT
-public:
- explicit VTabWidget(VNote *vnote, QWidget *parent = 0);
-
-signals:
- void tabModeChanged(const QString ¬ebook, const QString &relativePath,
- bool editMode, bool modifiable);
-
-public slots:
- void openFile(QJsonObject fileJson);
- // Close the file forcely
- void closeFile(QJsonObject fileJson);
- void editFile();
- void saveFile();
- void readFile();
- void saveAndReadFile();
- void handleNotebookRenamed(const QVector ¬ebooks, const QString &oldName,
- const QString &newName);
-
-private slots:
- void handleTabCloseRequest(int index);
- void onCurrentChanged(int index);
-
-private:
- void openWelcomePage();
- int insertTabWithData(int index, QWidget *page, const QJsonObject &tabData);
- int appendTabWithData(QWidget *page, const QJsonObject &tabData);
- int findTabByFile(const QString ¬ebook, const QString &relativePath) const;
- int openFileInTab(const QString ¬ebook, const QString &relativePath, bool modifiable);
- inline QString getFileName(const QString &relativePath) const;
-
- VNote *vnote;
-};
-
-inline QString VTabWidget::getFileName(const QString &path) const
-{
- return QFileInfo(QDir::cleanPath(path)).fileName();
-}
-
-#endif // VTABWIDGET_H