use QStackedWidget to hold QTextBrowser and VEdit

Use QTextBrowser to display file in read mode and VEdit to display file
in edit mode.

Signed-off-by: Le Tan <tamlokveer@gmail.com>
This commit is contained in:
Le Tan 2016-10-07 21:55:30 +08:00
parent b55ebe8f91
commit e3e18d040c
9 changed files with 305 additions and 157 deletions

View File

@ -22,7 +22,9 @@ SOURCES += main.cpp\
vfilelist.cpp \
vnewfiledialog.cpp \
vtabwidget.cpp \
vedit.cpp
vedit.cpp \
veditor.cpp \
vnotefile.cpp
HEADERS += vmainwindow.h \
vdirectorytree.h \
@ -33,7 +35,10 @@ HEADERS += vmainwindow.h \
vfilelist.h \
vnewfiledialog.h \
vtabwidget.h \
vedit.h
vedit.h \
veditor.h \
vconstants.h \
vnotefile.h
RESOURCES += \
vnote.qrc

6
vconstants.h Normal file
View File

@ -0,0 +1,6 @@
#ifndef VCONSTANTS_H
#define VCONSTANTS_H
enum class DocType { Html, Markdown };
#endif

144
vedit.cpp
View File

@ -1,154 +1,64 @@
#include <QtWidgets>
#include "vedit.h"
VEdit::VEdit(const QString &path, const QString &name, bool modifiable,
QWidget *parent)
: QTextEdit(parent), path(path), name(name), modifiable(modifiable)
VEdit::VEdit(VNoteFile *noteFile, QWidget *parent)
: QTextEdit(parent), noteFile(noteFile)
{
docType = isMarkdown() ? DocType::Markdown : DocType::Html;
fileText = readFileFromDisk(QDir(path).filePath(name));
showFileReadMode();
fileLoaded = true;
qDebug() << "VEdit:" << name << (docType == DocType::Markdown ? "Markdown" : "Html");
}
void VEdit::showFileReadMode()
{
setReadOnly(true);
switch (docType) {
case DocType::Html:
if (!fileLoaded) {
setHtml(fileText);
}
break;
case DocType::Markdown:
setText(fileText);
break;
default:
qWarning() << "error: unknown doc type" << int(docType);
}
}
void VEdit::showFileEditMode()
void VEdit::beginEdit()
{
setReadOnly(false);
switch (docType) {
switch (noteFile->docType) {
case DocType::Html:
if (!fileLoaded) {
setHtml(fileText);
}
setHtml(noteFile->content);
break;
case DocType::Markdown:
setText(fileText);
setPlainText(noteFile->content);
break;
default:
qWarning() << "error: unknown doc type" << int(docType);
qWarning() << "error: unknown doc type" << int(noteFile->docType);
}
}
QString VEdit::readFileFromDisk(const QString &filePath)
bool VEdit::tryEndEdit()
{
QFile file(filePath);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
qWarning() << "error: fail to read file" << filePath;
return QString();
}
QString fileText(file.readAll());
file.close();
qDebug() << "read file content:" << filePath;
return fileText;
return !document()->isModified();
}
bool VEdit::writeFileToDisk(const QString &filePath, const QString &text)
void VEdit::beginSave()
{
QFile file(filePath);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
qWarning() << "error: fail to open file" << filePath << "to write to";
return false;
}
QTextStream stream(&file);
stream << text;
file.close();
qDebug() << "write file content:" << filePath;
return true;
}
bool VEdit::requestClose()
{
readFile();
return isReadOnly();
}
void VEdit::editFile()
{
if (!modifiable || !isReadOnly()) {
return;
}
showFileEditMode();
}
void VEdit::readFile()
{
if (isReadOnly()) {
return;
}
if (document()->isModified()) {
QMessageBox msgBox(QMessageBox::Information, tr("Exit edit mode"),
QString("Note has been changed. Do you want to save it before exit?"));
msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::No | QMessageBox::Cancel);
msgBox.setDefaultButton(QMessageBox::Save);
int ret = msgBox.exec();
switch (ret) {
case QMessageBox::Save:
saveFile();
// Fall through
case QMessageBox::No:
showFileReadMode();
break;
case QMessageBox::Cancel:
break;
default:
qWarning() << "error: wrong return value from QMessageBox:" << ret;
}
} else {
showFileReadMode();
}
}
void VEdit::saveFile()
{
if (!modifiable || !document()->isModified()) {
if (!document()->isModified()) {
return;
}
switch (docType) {
switch (noteFile->docType) {
case DocType::Html:
fileText = toHtml();
writeFileToDisk(QDir(path).filePath(name), fileText);
noteFile->content = toHtml();
break;
case DocType::Markdown:
break;
default:
qWarning() << "error: unknown doc type" << int(docType);
qWarning() << "error: unknown doc type" << int(noteFile->docType);
}
}
void VEdit::endSave()
{
document()->setModified(false);
}
bool VEdit::isMarkdown()
void VEdit::reloadFile()
{
const QVector<QString> mdPostfix({"md", "markdown", "mkd"});
QStringList list = name.split('.', QString::SkipEmptyParts);
if (list.isEmpty()) {
return false;
switch (noteFile->docType) {
case DocType::Html:
setHtml(noteFile->content);
break;
case DocType::Markdown:
setPlainText(noteFile->content);
break;
default:
qWarning() << "error: unknown doc type" << int(noteFile->docType);
}
const QString &postfix = list.last();
for (int i = 0; i < mdPostfix.size(); ++i) {
if (postfix == mdPostfix[i]) {
return true;
}
}
return false;
}

35
vedit.h
View File

@ -3,20 +3,23 @@
#include <QTextEdit>
#include <QString>
#include "vconstants.h"
#include "vnotefile.h"
class VEdit : public QTextEdit
{
Q_OBJECT
public:
explicit VEdit(const QString &path, const QString &name, bool modifiable = false,
QWidget *parent = 0);
bool requestClose();
// Enter edit mode
void editFile();
// Enter read mode
void readFile();
// Save file
void saveFile();
VEdit(VNoteFile *noteFile, QWidget *parent = 0);
void beginEdit();
bool tryEndEdit();
// begin: sync the buffer to noteFile->content;
// end: setModified(false)
void beginSave();
void endSave();
void reloadFile();
signals:
@ -24,19 +27,7 @@ public slots:
private:
enum class DocType { Html, Markdown };
QString readFileFromDisk(const QString &filePath);
bool writeFileToDisk(const QString &filePath, const QString &text);
void showFileReadMode();
void showFileEditMode();
bool isMarkdown();
QString path;
QString name;
QString fileText;
DocType docType;
bool modifiable;
bool fileLoaded;
VNoteFile *noteFile;
};
#endif // VEDIT_H

167
veditor.cpp Normal file
View File

@ -0,0 +1,167 @@
#include <QtWidgets>
#include <QTextBrowser>
#include "veditor.h"
#include "vedit.h"
VEditor::VEditor(const QString &path, const QString &name, bool modifiable,
QWidget *parent)
: QStackedWidget(parent)
{
DocType docType = isMarkdown(name) ? DocType::Markdown : DocType::Html;
QString fileText = readFileFromDisk(QDir(path).filePath(name));
noteFile = new VNoteFile(path, name, fileText, docType, modifiable);
isEditMode = false;
setupUI();
showFileReadMode();
}
VEditor::~VEditor()
{
delete noteFile;
}
void VEditor::setupUI()
{
textEditor = new VEdit(noteFile);
textBrowser = new QTextBrowser();
addWidget(textBrowser);
addWidget(textEditor);
}
bool VEditor::isMarkdown(const QString &name)
{
const QVector<QString> mdPostfix({"md", "markdown", "mkd"});
QStringList list = name.split('.', QString::SkipEmptyParts);
if (list.isEmpty()) {
return false;
}
const QString &postfix = list.last();
for (int i = 0; i < mdPostfix.size(); ++i) {
if (postfix == mdPostfix[i]) {
return true;
}
}
return false;
}
QString VEditor::readFileFromDisk(const QString &filePath)
{
QFile file(filePath);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
qWarning() << "error: fail to read file" << filePath;
return QString();
}
QString fileText(file.readAll());
file.close();
qDebug() << "read file content:" << filePath;
return fileText;
}
bool VEditor::writeFileToDisk(const QString &filePath, const QString &text)
{
QFile file(filePath);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
qWarning() << "error: fail to open file" << filePath << "to write to";
return false;
}
QTextStream stream(&file);
stream << text;
file.close();
qDebug() << "write file content:" << filePath;
return true;
}
void VEditor::showFileReadMode()
{
isEditMode = false;
switch (noteFile->docType) {
case DocType::Html:
textBrowser->setHtml(noteFile->content);
break;
case DocType::Markdown:
break;
default:
qWarning() << "error: unknown doc type" << int(noteFile->docType);
}
setCurrentWidget(textBrowser);
}
void VEditor::showFileEditMode()
{
isEditMode = true;
textEditor->beginEdit();
setCurrentWidget(textEditor);
}
bool VEditor::requestClose()
{
readFile();
return !isEditMode;
}
void VEditor::editFile()
{
if (isEditMode || !noteFile->modifiable) {
return;
}
showFileEditMode();
}
void VEditor::readFile()
{
if (!isEditMode) {
return;
}
bool canExit = textEditor->tryEndEdit();
if (!canExit) {
// Need to save the changes
QMessageBox msgBox;
msgBox.setText("The note has been modified.");
msgBox.setInformativeText("Do you want to save your changes?");
msgBox.setIcon(QMessageBox::Information);
msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
msgBox.setDefaultButton(QMessageBox::Save);
int ret = msgBox.exec();
switch (ret) {
case QMessageBox::Save:
saveFile();
// Fall through
case QMessageBox::Discard:
textEditor->reloadFile();
break;
case QMessageBox::Cancel:
// Nothing to do if user cancel this action
return;
default:
qWarning() << "error: wrong return value from QMessageBox:" << ret;
return;
}
}
textEditor->setReadOnly(true);
showFileReadMode();
}
bool VEditor::saveFile()
{
if (!isEditMode || !noteFile->modifiable) {
return true;
}
textEditor->beginSave();
bool ret = writeFileToDisk(QDir(noteFile->path).filePath(noteFile->name),
noteFile->content);
if (!ret) {
QMessageBox msgBox(QMessageBox::Warning, tr("Fail to save to file"),
QString("Fail to write to disk when saving a note. Please try it again."));
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setDefaultButton(QMessageBox::Ok);
msgBox.exec();
return false;
}
textEditor->endSave();
return true;
}

40
veditor.h Normal file
View File

@ -0,0 +1,40 @@
#ifndef VEDITOR_H
#define VEDITOR_H
#include <QStackedWidget>
#include <QString>
#include "vconstants.h"
#include "vnotefile.h"
class QTextBrowser;
class VEdit;
class VEditor : public QStackedWidget
{
public:
VEditor(const QString &path, const QString &name, bool modifiable,
QWidget *parent = 0);
~VEditor();
bool requestClose();
// Enter edit mode
void editFile();
// Enter read mode
void readFile();
// Save file
bool saveFile();
private:
bool isMarkdown(const QString &name);
QString readFileFromDisk(const QString &filePath);
bool writeFileToDisk(const QString &filePath, const QString &text);
void setupUI();
void showFileReadMode();
void showFileEditMode();
VNoteFile *noteFile;
bool isEditMode;
QTextBrowser *textBrowser;
VEdit *textEditor;
};
#endif // VEDITOR_H

9
vnotefile.cpp Normal file
View File

@ -0,0 +1,9 @@
#include "vnotefile.h"
VNoteFile::VNoteFile(const QString &path, const QString &name,
const QString &content, DocType docType, bool modifiable)
: path(path), name(name), content(content), docType(docType),
modifiable(modifiable)
{
}

20
vnotefile.h Normal file
View File

@ -0,0 +1,20 @@
#ifndef VNOTEFILE_H
#define VNOTEFILE_H
#include <QString>
#include "vconstants.h"
class VNoteFile
{
public:
VNoteFile(const QString &path, const QString &name, const QString &content,
DocType docType, bool modifiable);
QString path;
QString name;
QString content;
DocType docType;
bool modifiable;
};
#endif // VNOTEFILE_H

View File

@ -1,7 +1,7 @@
#include <QtWidgets>
#include <QtDebug>
#include "vtabwidget.h"
#include "vedit.h"
#include "veditor.h"
VTabWidget::VTabWidget(const QString &welcomePageUrl, QWidget *parent)
: QTabWidget(parent), welcomePageUrl(welcomePageUrl)
@ -59,11 +59,11 @@ void VTabWidget::openFile(QJsonObject fileJson)
int VTabWidget::openFileInTab(const QString &path, const QString &name, bool modifiable)
{
VEdit *edit = new VEdit(path, name, modifiable);
VEditor *editor = new VEditor(path, name, modifiable);
QJsonObject tabJson;
tabJson["path"] = path;
tabJson["name"] = name;
int idx = appendTabWithData(edit, name, tabJson);
int idx = appendTabWithData(editor, name, tabJson);
setTabToolTip(idx, path);
return idx;
}
@ -85,32 +85,32 @@ int VTabWidget::findTabByFile(const QString &path, const QString &name)
void VTabWidget::handleTabCloseRequest(int index)
{
qDebug() << "request closing tab" << index;
VEdit *edit = dynamic_cast<VEdit *>(widget(index));
Q_ASSERT(edit);
bool ok = edit->requestClose();
VEditor *editor = dynamic_cast<VEditor *>(widget(index));
Q_ASSERT(editor);
bool ok = editor->requestClose();
if (ok) {
removeTab(index);
delete edit;
delete editor;
}
}
void VTabWidget::readFile()
{
VEdit *edit = dynamic_cast<VEdit *>(currentWidget());
Q_ASSERT(edit);
edit->readFile();
VEditor *editor = dynamic_cast<VEditor *>(currentWidget());
Q_ASSERT(editor);
editor->readFile();
}
void VTabWidget::editFile()
{
VEdit *edit = dynamic_cast<VEdit *>(currentWidget());
Q_ASSERT(edit);
edit->editFile();
VEditor *editor = dynamic_cast<VEditor *>(currentWidget());
Q_ASSERT(editor);
editor->editFile();
}
void VTabWidget::saveFile()
{
VEdit *edit = dynamic_cast<VEdit *>(currentWidget());
Q_ASSERT(edit);
edit->saveFile();
VEditor *editor = dynamic_cast<VEditor *>(currentWidget());
Q_ASSERT(editor);
editor->saveFile();
}