mirror of
https://gitee.com/vnotex/vnote.git
synced 2025-07-05 13:59:52 +08:00
support spliting edit windows
Signed-off-by: Le Tan <tamlokveer@gmail.com>
This commit is contained in:
parent
1bc95bcea0
commit
915c25e1a5
11
src/resources/icons/corner_menu.svg
Normal file
11
src/resources/icons/corner_menu.svg
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.2.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
width="512px" height="512px" viewBox="0 0 512 512" enable-background="new 0 0 512 512" xml:space="preserve">
|
||||||
|
<g id="Icon_3_">
|
||||||
|
<g>
|
||||||
|
<path d="M64,384h384v-42.666H64V384z M64,277.334h384v-42.667H64V277.334z M64,128v42.665h384V128H64z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 626 B |
10
src/resources/icons/remove_split.svg
Normal file
10
src/resources/icons/remove_split.svg
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.2.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
width="512px" height="512px" viewBox="0 0 512 512" enable-background="new 0 0 512 512" xml:space="preserve">
|
||||||
|
<path d="M458,210.409l-145.267-12.476L256,64l-56.743,133.934L54,210.409l110.192,95.524L131.161,448L256,372.686L380.83,448
|
||||||
|
l-33.021-142.066L458,210.409z M272.531,345.286L256,335.312l-16.53,9.973l-59.988,36.191l15.879-68.296l4.369-18.79l-14.577-12.637
|
||||||
|
l-52.994-45.939l69.836-5.998l19.206-1.65l7.521-17.75l27.276-64.381l27.27,64.379l7.52,17.751l19.208,1.65l69.846,5.998
|
||||||
|
l-52.993,45.939l-14.576,12.636l4.367,18.788l15.875,68.299L272.531,345.286z"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 935 B |
9
src/resources/icons/split_window.svg
Normal file
9
src/resources/icons/split_window.svg
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.2.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
width="512px" height="512px" viewBox="0 0 512 512" enable-background="new 0 0 512 512" xml:space="preserve">
|
||||||
|
<path d="M458,210.409l-145.267-12.476L256,64l-56.743,133.934L54,210.409l110.192,95.524L131.161,448L256,372.686L380.83,448
|
||||||
|
l-33.021-142.066L458,210.409z M272.531,345.287L256,335.313l-0.002-189.277l27.27,64.379l7.52,17.751l19.208,1.65l69.846,5.998
|
||||||
|
l-52.993,45.939l-14.576,12.636l4.367,18.788l15.875,68.299L272.531,345.287z"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 812 B |
10
src/src.pro
10
src/src.pro
@ -21,7 +21,6 @@ SOURCES += main.cpp\
|
|||||||
vconfigmanager.cpp \
|
vconfigmanager.cpp \
|
||||||
vfilelist.cpp \
|
vfilelist.cpp \
|
||||||
dialog/vnewfiledialog.cpp \
|
dialog/vnewfiledialog.cpp \
|
||||||
vtabwidget.cpp \
|
|
||||||
vedit.cpp \
|
vedit.cpp \
|
||||||
veditor.cpp \
|
veditor.cpp \
|
||||||
vnotefile.cpp \
|
vnotefile.cpp \
|
||||||
@ -40,7 +39,9 @@ SOURCES += main.cpp\
|
|||||||
veditoperations.cpp \
|
veditoperations.cpp \
|
||||||
vmdeditoperations.cpp \
|
vmdeditoperations.cpp \
|
||||||
dialog/vinsertimagedialog.cpp \
|
dialog/vinsertimagedialog.cpp \
|
||||||
vdownloader.cpp
|
vdownloader.cpp \
|
||||||
|
veditarea.cpp \
|
||||||
|
veditwindow.cpp
|
||||||
|
|
||||||
HEADERS += vmainwindow.h \
|
HEADERS += vmainwindow.h \
|
||||||
vdirectorytree.h \
|
vdirectorytree.h \
|
||||||
@ -50,7 +51,6 @@ HEADERS += vmainwindow.h \
|
|||||||
vconfigmanager.h \
|
vconfigmanager.h \
|
||||||
vfilelist.h \
|
vfilelist.h \
|
||||||
dialog/vnewfiledialog.h \
|
dialog/vnewfiledialog.h \
|
||||||
vtabwidget.h \
|
|
||||||
vedit.h \
|
vedit.h \
|
||||||
veditor.h \
|
veditor.h \
|
||||||
vconstants.h \
|
vconstants.h \
|
||||||
@ -71,7 +71,9 @@ HEADERS += vmainwindow.h \
|
|||||||
veditoperations.h \
|
veditoperations.h \
|
||||||
vmdeditoperations.h \
|
vmdeditoperations.h \
|
||||||
dialog/vinsertimagedialog.h \
|
dialog/vinsertimagedialog.h \
|
||||||
vdownloader.h
|
vdownloader.h \
|
||||||
|
veditarea.h \
|
||||||
|
veditwindow.h
|
||||||
|
|
||||||
RESOURCES += \
|
RESOURCES += \
|
||||||
vnote.qrc
|
vnote.qrc
|
||||||
|
274
src/veditarea.cpp
Normal file
274
src/veditarea.cpp
Normal file
@ -0,0 +1,274 @@
|
|||||||
|
#include <QtWidgets>
|
||||||
|
#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<QPair<int, int> > VEditArea::findTabsByFile(const QString ¬ebook, const QString &relativePath)
|
||||||
|
{
|
||||||
|
QVector<QPair<int, int> > 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<int, int> 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<VNotebook> ¬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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
70
src/veditarea.h
Normal file
70
src/veditarea.h
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
#ifndef VEDITAREA_H
|
||||||
|
#define VEDITAREA_H
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QJsonObject>
|
||||||
|
#include <QString>
|
||||||
|
#include <QFileInfo>
|
||||||
|
#include <QDir>
|
||||||
|
#include <QVector>
|
||||||
|
#include <QPair>
|
||||||
|
#include <QtDebug>
|
||||||
|
#include <QSplitter>
|
||||||
|
#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<VNotebook> ¬ebooks, const QString &oldName,
|
||||||
|
const QString &newName);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void handleSplitWindowRequest(VEditWindow *curWindow);
|
||||||
|
void handleRemoveSplitRequest(VEditWindow *curWindow);
|
||||||
|
void handleWindowFocused();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void setupUI();
|
||||||
|
QVector<QPair<int, int> > 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<VEditWindow *>(splitter->widget(windowIndex));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // VEDITAREA_H
|
@ -32,6 +32,9 @@ VEditor::VEditor(const QString &path, bool modifiable, QWidget *parent)
|
|||||||
setupUI();
|
setupUI();
|
||||||
|
|
||||||
showFileReadMode();
|
showFileReadMode();
|
||||||
|
|
||||||
|
connect(qApp, &QApplication::focusChanged,
|
||||||
|
this, &VEditor::handleFocusChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
VEditor::~VEditor()
|
VEditor::~VEditor()
|
||||||
@ -148,7 +151,7 @@ void VEditor::readFile()
|
|||||||
if (textEditor->isModified()) {
|
if (textEditor->isModified()) {
|
||||||
// Need to save the changes
|
// Need to save the changes
|
||||||
QMessageBox msgBox(this);
|
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.setInformativeText("Do you want to save your changes?");
|
||||||
msgBox.setIcon(QMessageBox::Information);
|
msgBox.setIcon(QMessageBox::Information);
|
||||||
msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
|
msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
|
||||||
@ -220,3 +223,15 @@ void VEditor::setupMarkdownPreview()
|
|||||||
|
|
||||||
addWidget(webPreviewer);
|
addWidget(webPreviewer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VEditor::focusTab()
|
||||||
|
{
|
||||||
|
currentWidget()->setFocus();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VEditor::handleFocusChanged(QWidget *old, QWidget *now)
|
||||||
|
{
|
||||||
|
if (isChild(now)) {
|
||||||
|
emit getFocused();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -16,6 +16,7 @@ class VNote;
|
|||||||
|
|
||||||
class VEditor : public QStackedWidget
|
class VEditor : public QStackedWidget
|
||||||
{
|
{
|
||||||
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
VEditor(const QString &path, bool modifiable, QWidget *parent = 0);
|
VEditor(const QString &path, bool modifiable, QWidget *parent = 0);
|
||||||
~VEditor();
|
~VEditor();
|
||||||
@ -29,6 +30,13 @@ public:
|
|||||||
|
|
||||||
inline bool getIsEditMode() const;
|
inline bool getIsEditMode() const;
|
||||||
inline bool isModified() const;
|
inline bool isModified() const;
|
||||||
|
void focusTab();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void getFocused();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void handleFocusChanged(QWidget *old, QWidget *now);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool isMarkdown(const QString &name);
|
bool isMarkdown(const QString &name);
|
||||||
@ -37,6 +45,7 @@ private:
|
|||||||
void showFileEditMode();
|
void showFileEditMode();
|
||||||
void setupMarkdownPreview();
|
void setupMarkdownPreview();
|
||||||
void previewByConverter();
|
void previewByConverter();
|
||||||
|
inline bool isChild(QObject *obj);
|
||||||
|
|
||||||
VNoteFile *noteFile;
|
VNoteFile *noteFile;
|
||||||
bool isEditMode;
|
bool isEditMode;
|
||||||
@ -57,4 +66,15 @@ inline bool VEditor::isModified() const
|
|||||||
return textEditor->isModified();
|
return textEditor->isModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool VEditor::isChild(QObject *obj)
|
||||||
|
{
|
||||||
|
while (obj) {
|
||||||
|
if (obj == this) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
obj = obj->parent();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
#endif // VEDITOR_H
|
#endif // VEDITOR_H
|
||||||
|
296
src/veditwindow.cpp
Normal file
296
src/veditwindow.cpp
Normal file
@ -0,0 +1,296 @@
|
|||||||
|
#include <QtWidgets>
|
||||||
|
#include <QtDebug>
|
||||||
|
#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<VNotebook> ¬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<VNotebook> ¬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);
|
||||||
|
}
|
84
src/veditwindow.h
Normal file
84
src/veditwindow.h
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
#ifndef VEDITWINDOW_H
|
||||||
|
#define VEDITWINDOW_H
|
||||||
|
|
||||||
|
#include <QTabWidget>
|
||||||
|
#include <QJsonObject>
|
||||||
|
#include <QString>
|
||||||
|
#include <QFileInfo>
|
||||||
|
#include <QDir>
|
||||||
|
#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<VNotebook> ¬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<VEditor *>(widget(tabIndex));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // VEDITWINDOW_H
|
@ -4,11 +4,11 @@
|
|||||||
#include "vdirectorytree.h"
|
#include "vdirectorytree.h"
|
||||||
#include "vnote.h"
|
#include "vnote.h"
|
||||||
#include "vfilelist.h"
|
#include "vfilelist.h"
|
||||||
#include "vtabwidget.h"
|
|
||||||
#include "vconfigmanager.h"
|
#include "vconfigmanager.h"
|
||||||
#include "dialog/vnewnotebookdialog.h"
|
#include "dialog/vnewnotebookdialog.h"
|
||||||
#include "dialog/vnotebookinfodialog.h"
|
#include "dialog/vnotebookinfodialog.h"
|
||||||
#include "utils/vutils.h"
|
#include "utils/vutils.h"
|
||||||
|
#include "veditarea.h"
|
||||||
|
|
||||||
extern VConfigManager vconfig;
|
extern VConfigManager vconfig;
|
||||||
|
|
||||||
@ -79,15 +79,14 @@ void VMainWindow::setupUI()
|
|||||||
fileList = new VFileList(vnote);
|
fileList = new VFileList(vnote);
|
||||||
fileList->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Expanding);
|
fileList->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Expanding);
|
||||||
|
|
||||||
// Editor tab widget
|
editArea = new VEditArea(vnote);
|
||||||
tabs = new VTabWidget(vnote);
|
editArea->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||||
tabs->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
|
||||||
|
|
||||||
// Main Splitter
|
// Main Splitter
|
||||||
mainSplitter = new QSplitter();
|
mainSplitter = new QSplitter();
|
||||||
mainSplitter->addWidget(nbContainer);
|
mainSplitter->addWidget(nbContainer);
|
||||||
mainSplitter->addWidget(fileList);
|
mainSplitter->addWidget(fileList);
|
||||||
mainSplitter->addWidget(tabs);
|
mainSplitter->addWidget(editArea);
|
||||||
mainSplitter->setStretchFactor(0, 0);
|
mainSplitter->setStretchFactor(0, 0);
|
||||||
mainSplitter->setStretchFactor(1, 0);
|
mainSplitter->setStretchFactor(1, 0);
|
||||||
mainSplitter->setStretchFactor(2, 1);
|
mainSplitter->setStretchFactor(2, 1);
|
||||||
@ -106,14 +105,14 @@ void VMainWindow::setupUI()
|
|||||||
this, &VMainWindow::handleFileListDirectoryChanged);
|
this, &VMainWindow::handleFileListDirectoryChanged);
|
||||||
|
|
||||||
connect(fileList, &VFileList::fileClicked,
|
connect(fileList, &VFileList::fileClicked,
|
||||||
tabs, &VTabWidget::openFile);
|
editArea, &VEditArea::openFile);
|
||||||
connect(fileList, &VFileList::fileDeleted,
|
connect(fileList, &VFileList::fileDeleted,
|
||||||
tabs, &VTabWidget::closeFile);
|
editArea, &VEditArea::closeFile);
|
||||||
connect(fileList, &VFileList::fileCreated,
|
connect(fileList, &VFileList::fileCreated,
|
||||||
tabs, &VTabWidget::openFile);
|
editArea, &VEditArea::openFile);
|
||||||
connect(vnote, &VNote::notebooksRenamed,
|
connect(vnote, &VNote::notebooksRenamed,
|
||||||
tabs, &VTabWidget::handleNotebookRenamed);
|
editArea, &VEditArea::handleNotebookRenamed);
|
||||||
connect(tabs, &VTabWidget::tabModeChanged,
|
connect(editArea, &VEditArea::curTabStatusChanged,
|
||||||
this, &VMainWindow::updateToolbarFromTabChage);
|
this, &VMainWindow::updateToolbarFromTabChage);
|
||||||
|
|
||||||
connect(newNotebookBtn, &QPushButton::clicked,
|
connect(newNotebookBtn, &QPushButton::clicked,
|
||||||
@ -160,26 +159,26 @@ void VMainWindow::initActions()
|
|||||||
tr("&Edit"), this);
|
tr("&Edit"), this);
|
||||||
editNoteAct->setStatusTip(tr("Edit current note"));
|
editNoteAct->setStatusTip(tr("Edit current note"));
|
||||||
connect(editNoteAct, &QAction::triggered,
|
connect(editNoteAct, &QAction::triggered,
|
||||||
tabs, &VTabWidget::editFile);
|
editArea, &VEditArea::editFile);
|
||||||
|
|
||||||
discardExitAct = new QAction(QIcon(":/resources/icons/discard_exit.svg"),
|
discardExitAct = new QAction(QIcon(":/resources/icons/discard_exit.svg"),
|
||||||
tr("Discard changes and exit"), this);
|
tr("Discard changes and exit"), this);
|
||||||
discardExitAct->setStatusTip(tr("Discard changes and exit edit mode"));
|
discardExitAct->setStatusTip(tr("Discard changes and exit edit mode"));
|
||||||
connect(discardExitAct, &QAction::triggered,
|
connect(discardExitAct, &QAction::triggered,
|
||||||
tabs, &VTabWidget::readFile);
|
editArea, &VEditArea::readFile);
|
||||||
|
|
||||||
saveExitAct = new QAction(QIcon(":/resources/icons/save_exit.svg"),
|
saveExitAct = new QAction(QIcon(":/resources/icons/save_exit.svg"),
|
||||||
tr("Save changes and exit"), this);
|
tr("Save changes and exit"), this);
|
||||||
saveExitAct->setStatusTip(tr("Save changes and exit edit mode"));
|
saveExitAct->setStatusTip(tr("Save changes and exit edit mode"));
|
||||||
connect(saveExitAct, &QAction::triggered,
|
connect(saveExitAct, &QAction::triggered,
|
||||||
tabs, &VTabWidget::saveAndReadFile);
|
editArea, &VEditArea::saveAndReadFile);
|
||||||
|
|
||||||
saveNoteAct = new QAction(QIcon(":/resources/icons/save_note.svg"),
|
saveNoteAct = new QAction(QIcon(":/resources/icons/save_note.svg"),
|
||||||
tr("&Save"), this);
|
tr("&Save"), this);
|
||||||
saveNoteAct->setStatusTip(tr("Save current note"));
|
saveNoteAct->setStatusTip(tr("Save current note"));
|
||||||
saveNoteAct->setShortcut(QKeySequence::Save);
|
saveNoteAct->setShortcut(QKeySequence::Save);
|
||||||
connect(saveNoteAct, &QAction::triggered,
|
connect(saveNoteAct, &QAction::triggered,
|
||||||
tabs, &VTabWidget::saveFile);
|
editArea, &VEditArea::saveFile);
|
||||||
|
|
||||||
viewAct = new QActionGroup(this);
|
viewAct = new QActionGroup(this);
|
||||||
twoPanelViewAct = new QAction(QIcon(":/resources/icons/two_panels.svg"),
|
twoPanelViewAct = new QAction(QIcon(":/resources/icons/two_panels.svg"),
|
||||||
|
@ -11,12 +11,12 @@ class QListWidget;
|
|||||||
class QTabWidget;
|
class QTabWidget;
|
||||||
class QToolBar;
|
class QToolBar;
|
||||||
class VNote;
|
class VNote;
|
||||||
class VTabWidget;
|
|
||||||
class QAction;
|
class QAction;
|
||||||
class QPushButton;
|
class QPushButton;
|
||||||
class VNotebook;
|
class VNotebook;
|
||||||
class QActionGroup;
|
class QActionGroup;
|
||||||
class VFileList;
|
class VFileList;
|
||||||
|
class VEditArea;
|
||||||
|
|
||||||
class VMainWindow : public QMainWindow
|
class VMainWindow : public QMainWindow
|
||||||
{
|
{
|
||||||
@ -65,6 +65,7 @@ private:
|
|||||||
|
|
||||||
// If true, comboBox changes will not trigger any signal out
|
// If true, comboBox changes will not trigger any signal out
|
||||||
bool notebookComboMuted;
|
bool notebookComboMuted;
|
||||||
|
VNote *vnote;
|
||||||
|
|
||||||
QLabel *notebookLabel;
|
QLabel *notebookLabel;
|
||||||
QLabel *directoryLabel;
|
QLabel *directoryLabel;
|
||||||
@ -77,9 +78,8 @@ private:
|
|||||||
QPushButton *dirInfoBtn;
|
QPushButton *dirInfoBtn;
|
||||||
VFileList *fileList;
|
VFileList *fileList;
|
||||||
VDirectoryTree *directoryTree;
|
VDirectoryTree *directoryTree;
|
||||||
VTabWidget *tabs;
|
|
||||||
QSplitter *mainSplitter;
|
QSplitter *mainSplitter;
|
||||||
VNote *vnote;
|
VEditArea *editArea;
|
||||||
|
|
||||||
// Actions
|
// Actions
|
||||||
QAction *newNoteAct;
|
QAction *newNoteAct;
|
||||||
|
@ -53,5 +53,8 @@
|
|||||||
<file>resources/icons/expand.svg</file>
|
<file>resources/icons/expand.svg</file>
|
||||||
<file>resources/icons/two_panels.svg</file>
|
<file>resources/icons/two_panels.svg</file>
|
||||||
<file>resources/icons/one_panel.svg</file>
|
<file>resources/icons/one_panel.svg</file>
|
||||||
|
<file>resources/icons/split_window.svg</file>
|
||||||
|
<file>resources/icons/corner_menu.svg</file>
|
||||||
|
<file>resources/icons/remove_split.svg</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
@ -1,210 +0,0 @@
|
|||||||
#include <QtWidgets>
|
|
||||||
#include <QtDebug>
|
|
||||||
#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<VNotebook> ¬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<VEditor *>(widget(index));
|
|
||||||
Q_ASSERT(editor);
|
|
||||||
bool ok = editor->requestClose();
|
|
||||||
if (ok) {
|
|
||||||
removeTab(index);
|
|
||||||
delete editor;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void VTabWidget::readFile()
|
|
||||||
{
|
|
||||||
VEditor *editor = dynamic_cast<VEditor *>(currentWidget());
|
|
||||||
Q_ASSERT(editor);
|
|
||||||
editor->readFile();
|
|
||||||
onCurrentChanged(currentIndex());
|
|
||||||
}
|
|
||||||
|
|
||||||
void VTabWidget::saveAndReadFile()
|
|
||||||
{
|
|
||||||
saveFile();
|
|
||||||
readFile();
|
|
||||||
onCurrentChanged(currentIndex());
|
|
||||||
}
|
|
||||||
|
|
||||||
void VTabWidget::editFile()
|
|
||||||
{
|
|
||||||
VEditor *editor = dynamic_cast<VEditor *>(currentWidget());
|
|
||||||
Q_ASSERT(editor);
|
|
||||||
editor->editFile();
|
|
||||||
onCurrentChanged(currentIndex());
|
|
||||||
}
|
|
||||||
|
|
||||||
void VTabWidget::saveFile()
|
|
||||||
{
|
|
||||||
VEditor *editor = dynamic_cast<VEditor *>(currentWidget());
|
|
||||||
Q_ASSERT(editor);
|
|
||||||
editor->saveFile();
|
|
||||||
}
|
|
||||||
|
|
||||||
void VTabWidget::handleNotebookRenamed(const QVector<VNotebook> ¬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);
|
|
||||||
}
|
|
@ -1,54 +0,0 @@
|
|||||||
#ifndef VTABWIDGET_H
|
|
||||||
#define VTABWIDGET_H
|
|
||||||
|
|
||||||
#include <QTabWidget>
|
|
||||||
#include <QJsonObject>
|
|
||||||
#include <QString>
|
|
||||||
#include <QFileInfo>
|
|
||||||
#include <QDir>
|
|
||||||
#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<VNotebook> ¬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
|
|
Loading…
x
Reference in New Issue
Block a user