* add file type combobox in NewNoteDialog

* add SectionNumberStyle
This commit is contained in:
Le Tan 2021-01-07 04:41:45 -08:00 committed by GitHub
parent 9dd83a6f2f
commit 6503b433e1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 433 additions and 126 deletions

@ -1 +1 @@
Subproject commit 5fe5d4be7191de58fd1c2411b1ff97bcbecfaa3d
Subproject commit 69bd57656ccac8cf75502506be0c87d80d86e577

View File

@ -1,54 +1,123 @@
#include "filetypehelper.h"
#include <QFileInfo>
#include <QDebug>
#include <utils/fileutils.h>
#include "buffer.h"
using namespace vnotex;
const FileType FileTypeHelper::s_markdownFileType = "markdown";
FileTypeHelper::FileTypeHelper()
{
setupBuiltInTypes();
const FileType FileTypeHelper::s_textFileType = "text";
// TODO: read configuration file.
const FileType FileTypeHelper::s_unknownFileType = "unknown";
setupSuffixTypeMap();
}
QSharedPointer<QMap<QString, FileType>> FileTypeHelper::s_fileTypeMap;
void FileTypeHelper::setupBuiltInTypes()
{
{
FileType type;
type.m_type = Type::Markdown;
type.m_displayName = Buffer::tr("Markdown");
type.m_typeName = QStringLiteral("Markdown");
type.m_suffixes << QStringLiteral("md") << QStringLiteral("mkd") << QStringLiteral("markdown");
m_fileTypes.push_back(type);
}
FileType FileTypeHelper::fileType(const QString &p_filePath)
{
FileType type;
type.m_type = Type::Text;
type.m_typeName = QStringLiteral("Text");
type.m_displayName = Buffer::tr("Text");
type.m_suffixes << QStringLiteral("txt") << QStringLiteral("text") << QStringLiteral("log");
m_fileTypes.push_back(type);
}
{
FileType type;
type.m_type = Type::Others;
type.m_typeName = QStringLiteral("Others");
type.m_displayName = Buffer::tr("Others");
m_fileTypes.push_back(type);
}
}
const FileType &FileTypeHelper::getFileType(const QString &p_filePath) const
{
Q_ASSERT(!p_filePath.isEmpty());
if (!s_fileTypeMap) {
init();
}
QFileInfo fi(p_filePath);
auto suffix = fi.suffix().toLower();
auto it = s_fileTypeMap->find(suffix);
if (it != s_fileTypeMap->end()) {
return it.value();
auto it = m_suffixTypeMap.find(suffix);
if (it != m_suffixTypeMap.end()) {
return m_fileTypes.at(it.value());
}
// Treat all unknown text files as plain text files.
if (FileUtils::isText(p_filePath)) {
return s_fileTypeMap->value(QStringLiteral("txt"));
return m_fileTypes[Type::Text];
}
return s_unknownFileType;
return m_fileTypes[Type::Others];
}
#define ADD(x, y) s_fileTypeMap->insert((x), (y))
void FileTypeHelper::init()
const FileType &FileTypeHelper::getFileTypeBySuffix(const QString &p_suffix) const
{
// TODO: load mapping from configuration file.
s_fileTypeMap.reset(new QMap<QString, FileType>());
ADD(QStringLiteral("md"), s_markdownFileType);
ADD(QStringLiteral("markdown"), s_markdownFileType);
ADD(QStringLiteral("mkd"), s_markdownFileType);
ADD(QStringLiteral("txt"), s_textFileType);
ADD(QStringLiteral("text"), s_textFileType);
ADD(QStringLiteral("log"), s_textFileType);
auto it = m_suffixTypeMap.find(p_suffix.toLower());
if (it != m_suffixTypeMap.end()) {
return m_fileTypes.at(it.value());
} else {
return m_fileTypes[Type::Others];
}
}
#define ADD(x, y) m_suffixTypeMap.insert((x), (y))
void FileTypeHelper::setupSuffixTypeMap()
{
for (int i = 0; i < m_fileTypes.size(); ++i) {
for (const auto &suffix : m_fileTypes[i].m_suffixes) {
if (m_suffixTypeMap.contains(suffix)) {
qWarning() << "suffix conflicts detected" << suffix << m_fileTypes[i].m_type;
}
m_suffixTypeMap.insert(suffix, i);
}
}
}
const QVector<FileType> &FileTypeHelper::getAllFileTypes() const
{
return m_fileTypes;
}
const FileType &FileTypeHelper::getFileType(Type p_type) const
{
return m_fileTypes[p_type];
}
const FileTypeHelper &FileTypeHelper::getInst()
{
static FileTypeHelper helper;
return helper;
}
bool FileTypeHelper::checkFileType(const QString &p_filePath, Type p_type) const
{
return getFileType(p_filePath).m_type == static_cast<int>(p_type);
}
const FileType &FileTypeHelper::getFileTypeByName(const QString &p_typeName) const
{
for (const auto &ft : m_fileTypes) {
if (ft.m_typeName == p_typeName) {
return ft;
}
}
Q_ASSERT(false);
return m_fileTypes[Type::Others];
}

View File

@ -3,30 +3,65 @@
#include <QString>
#include <QMap>
#include <QSharedPointer>
#include <QVector>
namespace vnotex
{
typedef QString FileType;
class FileType
{
public:
// FileTypeHelper::Type.
int m_type = -1;
QString m_typeName;
QString m_displayName;
QStringList m_suffixes;
QString preferredSuffix() const
{
return m_suffixes.isEmpty() ? QString() : m_suffixes.first();
}
};
// Map file suffix to file type.
class FileTypeHelper
{
public:
FileTypeHelper() = delete;
enum Type
{
Markdown = 0,
Text,
Others
};
static FileType fileType(const QString &p_filePath);
const FileType &getFileType(const QString &p_filePath) const;
static const FileType s_markdownFileType;
const FileType &getFileType(Type p_type) const;
static const FileType s_textFileType;
const FileType &getFileTypeByName(const QString &p_typeName) const;
static const FileType s_unknownFileType;
const FileType &getFileTypeBySuffix(const QString &p_suffix) const;
const QVector<FileType> &getAllFileTypes() const;
bool checkFileType(const QString &p_filePath, Type p_type) const;
static const FileTypeHelper &getInst();
private:
static void init();
FileTypeHelper();
static QSharedPointer<QMap<QString, FileType>> s_fileTypeMap;
void setupBuiltInTypes();
void setupSuffixTypeMap();
// Built-in Type could be accessed via enum Type.
QVector<FileType> m_fileTypes;
// suffix -> index of m_fileTypes.
// TODO: handle suffix conflicts.
QMap<QString, int> m_suffixTypeMap;
};
} // ns vnotex

View File

@ -37,13 +37,15 @@ void BufferMgr::initBufferServer()
{
m_bufferServer.reset(new NameBasedServer<IBufferFactory>);
const auto &helper = FileTypeHelper::getInst();
// Markdown.
auto markdownFactory = QSharedPointer<MarkdownBufferFactory>::create();
m_bufferServer->registerItem(FileTypeHelper::s_markdownFileType, markdownFactory);
m_bufferServer->registerItem(helper.getFileType(FileTypeHelper::Markdown).m_typeName, markdownFactory);
// Text.
auto textFactory = QSharedPointer<TextBufferFactory>::create();
m_bufferServer->registerItem(FileTypeHelper::s_textFileType, textFactory);
m_bufferServer->registerItem(helper.getFileType(FileTypeHelper::Text).m_typeName, textFactory);
}
void BufferMgr::open(Node *p_node, const QSharedPointer<FileOpenParameters> &p_paras)
@ -59,11 +61,11 @@ void BufferMgr::open(Node *p_node, const QSharedPointer<FileOpenParameters> &p_p
auto buffer = findBuffer(p_node);
if (!buffer) {
auto nodePath = p_node->fetchAbsolutePath();
auto fileType = FileTypeHelper::fileType(nodePath);
auto fileType = FileTypeHelper::getInst().getFileType(nodePath).m_typeName;
auto factory = m_bufferServer->getItem(fileType);
if (!factory) {
// No factory to open this file type.
qInfo() << "File will be opened by system:" << nodePath;
qInfo() << "file will be opened by default program" << nodePath;
WidgetUtils::openUrlByDesktop(QUrl::fromLocalFile(nodePath));
return;
}
@ -102,11 +104,11 @@ void BufferMgr::open(const QString &p_filePath, const QSharedPointer<FileOpenPar
auto buffer = findBuffer(p_filePath);
if (!buffer) {
// Open it as external file.
auto fileType = FileTypeHelper::fileType(p_filePath);
auto fileType = FileTypeHelper::getInst().getFileType(p_filePath).m_typeName;
auto factory = m_bufferServer->getItem(fileType);
if (!factory) {
// No factory to open this file type.
qInfo() << "File will be opened by system:" << p_filePath;
qInfo() << "file will be opened by default program" << p_filePath;
WidgetUtils::openUrlByDesktop(QUrl::fromLocalFile(p_filePath));
return;
}

View File

@ -37,6 +37,7 @@ void MarkdownEditorConfig::init(const QJsonObject &p_app, const QJsonObject &p_u
m_sectionNumberMode = stringToSectionNumberMode(READSTR(QStringLiteral("section_number")));
m_sectionNumberBaseLevel = READINT(QStringLiteral("section_number_base_level"));
m_sectionNumberStyle = stringToSectionNumberStyle(READSTR(QStringLiteral("section_number_style")));
m_constrainImageWidthEnabled = READBOOL(QStringLiteral("constrain_image_width"));
m_constrainInPlacePreviewWidthEnabled = READBOOL(QStringLiteral("constrain_inplace_preview_width"));
@ -61,6 +62,7 @@ QJsonObject MarkdownEditorConfig::toJson() const
obj[QStringLiteral("section_number")] = sectionNumberModeToString(m_sectionNumberMode);
obj[QStringLiteral("section_number_base_level")] = m_sectionNumberBaseLevel;
obj[QStringLiteral("section_number_style")] = sectionNumberStyleToString(m_sectionNumberStyle);
obj[QStringLiteral("constrain_image_width")] = m_constrainImageWidthEnabled;
obj[QStringLiteral("constrain_inplace_preview_width")] = m_constrainInPlacePreviewWidthEnabled;
@ -267,6 +269,27 @@ MarkdownEditorConfig::SectionNumberMode MarkdownEditorConfig::stringToSectionNum
}
}
QString MarkdownEditorConfig::sectionNumberStyleToString(SectionNumberStyle p_style) const
{
switch (p_style) {
case SectionNumberStyle::DigDotDig:
return QStringLiteral("digdotdig");
default:
return QStringLiteral("digdotdigdot");
}
}
MarkdownEditorConfig::SectionNumberStyle MarkdownEditorConfig::stringToSectionNumberStyle(const QString &p_str) const
{
auto style = p_str.toLower();
if (style == QStringLiteral("digdotdig")) {
return SectionNumberStyle::DigDotDig;
} else {
return SectionNumberStyle::DigDotDigDot;
}
}
MarkdownEditorConfig::SectionNumberMode MarkdownEditorConfig::getSectionNumberMode() const
{
return m_sectionNumberMode;
@ -286,3 +309,13 @@ void MarkdownEditorConfig::setSectionNumberBaseLevel(int p_level)
{
updateConfig(m_sectionNumberBaseLevel, p_level, this);
}
MarkdownEditorConfig::SectionNumberStyle MarkdownEditorConfig::getSectionNumberStyle() const
{
return m_sectionNumberStyle;
}
void MarkdownEditorConfig::setSectionNumberStyle(SectionNumberStyle p_style)
{
updateConfig(m_sectionNumberStyle, p_style, this);
}

View File

@ -22,6 +22,14 @@ namespace vnotex
Edit
};
enum SectionNumberStyle
{
// 1.1.
DigDotDigDot,
// 1.1
DigDotDig
};
MarkdownEditorConfig(ConfigMgr *p_mgr,
IConfig *p_topConfig,
const QSharedPointer<TextEditorConfig> &p_textEditorConfig);
@ -58,6 +66,9 @@ namespace vnotex
int getSectionNumberBaseLevel() const;
void setSectionNumberBaseLevel(int p_level);
SectionNumberStyle getSectionNumberStyle() const;
void setSectionNumberStyle(SectionNumberStyle p_style);
bool getConstrainImageWidthEnabled() const;
void setConstrainImageWidthEnabled(bool p_enabled);
@ -88,6 +99,9 @@ namespace vnotex
QString sectionNumberModeToString(SectionNumberMode p_mode) const;
SectionNumberMode stringToSectionNumberMode(const QString &p_str) const;
QString sectionNumberStyleToString(SectionNumberStyle p_style) const;
SectionNumberStyle stringToSectionNumberStyle(const QString &p_str) const;
QSharedPointer<TextEditorConfig> m_textEditorConfig;
ViewerResource m_viewerResource;
@ -112,6 +126,9 @@ namespace vnotex
// 1 based.
int m_sectionNumberBaseLevel = 2;
// Section number style.
SectionNumberStyle m_sectionNumberStyle = SectionNumberStyle::DigDotDigDot;
// Whether enable image width constraint.
bool m_constrainImageWidthEnabled = true;

View File

@ -23,8 +23,8 @@ void NodeContentMediaUtils::copyMediaFiles(const Node *p_node,
const QString &p_destFilePath)
{
Q_ASSERT(p_node->getType() == Node::Type::File);
auto fileType = FileTypeHelper::fileType(p_node->fetchAbsolutePath());
if (fileType == QStringLiteral("markdown")) {
const auto &fileType = FileTypeHelper::getInst().getFileType(p_node->fetchAbsolutePath());
if (fileType.m_type == FileTypeHelper::Markdown) {
copyMarkdownMediaFiles(p_node->read(),
PathUtils::parentDirPath(p_node->fetchContentPath()),
p_backend,
@ -36,8 +36,8 @@ void NodeContentMediaUtils::copyMediaFiles(const QString &p_filePath,
INotebookBackend *p_backend,
const QString &p_destFilePath)
{
auto fileType = FileTypeHelper::fileType(p_filePath);
if (fileType == QStringLiteral("markdown")) {
const auto &fileType = FileTypeHelper::getInst().getFileType(p_filePath);
if (fileType.m_type == FileTypeHelper::Markdown) {
copyMarkdownMediaFiles(FileUtils::readTextFile(p_filePath),
PathUtils::parentDirPath(p_filePath),
p_backend,
@ -112,8 +112,8 @@ void NodeContentMediaUtils::copyMarkdownMediaFiles(const QString &p_content,
void NodeContentMediaUtils::removeMediaFiles(const Node *p_node)
{
Q_ASSERT(p_node->getType() == Node::Type::File);
auto fileType = FileTypeHelper::fileType(p_node->fetchAbsolutePath());
if (fileType == QStringLiteral("markdown")) {
const auto &fileType = FileTypeHelper::getInst().getFileType(p_node->fetchAbsolutePath());
if (fileType.m_type == FileTypeHelper::Markdown) {
removeMarkdownMediaFiles(p_node);
}
}
@ -162,8 +162,8 @@ void NodeContentMediaUtils::copyAttachment(Node *p_node,
return;
}
auto fileType = FileTypeHelper::fileType(p_node->fetchAbsolutePath());
if (fileType == QStringLiteral("markdown")) {
const auto &fileType = FileTypeHelper::getInst().getFileType(p_node->fetchAbsolutePath());
if (fileType.m_type == FileTypeHelper::Markdown) {
fixMarkdownLinks(srcAttachmentFolderPath, p_backend, p_destFilePath, p_destAttachmentFolderPath);
}
}

View File

@ -1 +1 @@
<svg t="1600000206395" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="9662" width="512" height="512"><path d="M0 616.192l321.344 206.624 0-149.152L130.016 555.52l191.328-118.144L321.344 287.2 0 494.88 0 616.192zM389.312 896l110.592 0 162.048-768-111.328 0L389.312 896zM702.688 287.2l0 150.176 191.264 118.144-191.264 118.112 0 149.152L1024 616.192l0-121.312L702.688 287.2z" p-id="9663" fill="#000000"></path></svg>
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1609914714422" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7578" width="512" height="512" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><style type="text/css"></style></defs><path d="M516.551 695.182c0 5.006 3.869 9.102 8.533 9.102h210.49c4.664 0 8.533-4.096 8.533-9.102V640.57c0-5.006-3.869-9.102-8.534-9.102H525.084c-4.664 0-8.533 4.096-8.533 9.102v54.613z m-221.753 6.94L513.252 518.94c4.323-3.64 4.323-10.353 0-13.994L294.798 321.877c-5.916-5.006-14.905-0.796-14.905 6.94v71.34c0 2.73 1.138 5.233 3.3 6.94L408.12 512 283.193 616.903c-2.048 1.707-3.3 4.324-3.3 6.94v71.34c0 7.736 8.989 11.946 14.905 6.94z" p-id="7579" fill="#000000"></path><path d="M930.702 56.889H93.298c-20.139 0-36.41 16.27-36.41 36.409v837.404c0 20.139 16.271 36.41 36.41 36.41h837.404c20.139 0 36.41-16.271 36.41-36.41V93.298c0-20.139-16.271-36.41-36.41-36.41z m-45.51 828.302H138.808V138.81H885.19V885.19z" p-id="7580" fill="#000000"></path></svg>

Before

Width:  |  Height:  |  Size: 460 B

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -228,8 +228,11 @@
"insert_file_name_as_title" : true,
"//comment" : "none/read/edit",
"section_number" : "read",
"//comment" : "base level to start section numbering, valid only in edit mode",
"//comment" : "Base level to start section numbering, valid only in edit mode",
"section_number_base_level" : 2,
"//comment" : "Style of the section number in edit mode",
"//comment" : "digdotdigdot/digdotdig",
"section_number_style" : "digdotdigdot",
"//comment" : "Whether enable image width constraint",
"constrain_image_width" : true,
"//comment" : "Whether enable in-place preview width constraint",

View File

@ -1079,3 +1079,18 @@ QSizeGrip {
width: 16px;
height: 16px;
}
/* ViewWindow */
vnotex--ViewWindow QToolBar[ViewWindowToolBar="true"] {
background-color: @widgets#viewwindow#toolbar#bg;
}
/* ViewSplit */
vnotex--ViewSplit QTabBar::tab:selected {
color: @widgets#viewsplit#tabbar#tab#selected#fg;
background-color: @widgets#viewsplit#tabbar#tab#selected#bg;
}
vte--VTextEdit {
border: none;
}

View File

@ -233,6 +233,14 @@
"active" : {
"fg" : "@base#icon#fg"
}
},
"tabbar" : {
"tab" : {
"selected" : {
"fg" : "@base#content#fg",
"bg" : "@base#content#bg"
}
}
}
},
"qmainwindow" : {
@ -403,8 +411,8 @@
"bg" : "@base#hover#bg"
},
"selected" : {
"fg" : "@base#selected#fg",
"bg" : "@base#selected#bg",
"fg" : "@base#content#fg",
"bg" : "@base#content#bg",
"border" : "@base#master#bg"
}
}
@ -584,6 +592,11 @@
"border" : "@widgets#qslider#handle#border",
"bg" : "@base#master#alt"
}
},
"viewwindow" : {
"toolbar" : {
"bg" : "@base#content#bg"
}
}
}
}

View File

@ -108,7 +108,7 @@
},
"HRULE" : {
"text-color" : "#abb2bf",
"background-color" : "#493134"
"background-color" : "#864046"
},
"LIST_BULLET" : {
"text-color" : "#e06c75",

View File

@ -22,27 +22,27 @@
#vx-content.vx-section-number h2::before {
counter-increment: section1;
content: counter(section1) " ";
content: counter(section1) ". ";
}
#vx-content.vx-section-number h3::before {
counter-increment: section2;
content: counter(section1) "." counter(section2) " ";
content: counter(section1) "." counter(section2) ". ";
}
#vx-content.vx-section-number h4::before {
counter-increment: section3;
content: counter(section1) "." counter(section2) "." counter(section3) " ";
content: counter(section1) "." counter(section2) "." counter(section3) ". ";
}
#vx-content.vx-section-number h5::before {
counter-increment: section4;
content: counter(section1) "." counter(section2) "." counter(section3) "." counter(section4) " ";
content: counter(section1) "." counter(section2) "." counter(section3) "." counter(section4) ". ";
}
#vx-content.vx-section-number h6::before {
counter-increment: section5;
content: counter(section1) "." counter(section2) "." counter(section3) "." counter(section4) "." counter(section5) " ";
content: counter(section1) "." counter(section2) "." counter(section3) "." counter(section4) "." counter(section5) ". ";
}
#vx-content.vx-constrain-image-width img {

View File

@ -61,7 +61,9 @@ class MarkJs {
'className': this.className,
'caseSensitive': p_options.caseSensitive,
'accuracy': p_options.wholeWordOnly ? 'exactly' : 'partially',
'done': callbackFunc(this, p_text, p_options)
'done': callbackFunc(this, p_text, p_options),
// Ignore SVG, or SVG will be corrupted.
'exclude': ['svg *']
}
if (p_options.regularExpression) {

View File

@ -111,6 +111,6 @@ class Utils {
}
static headingSequenceRegExp() {
return /^\d{1,3}(?:\.\d+)*\.? /;
return /^\d{1,3}(?:\.\d+)*\. /;
}
}

View File

@ -22,6 +22,7 @@
#include <QMenu>
#include <QDebug>
#include <QFormLayout>
#include <QLineEdit>
using namespace vnotex;
@ -366,3 +367,10 @@ QFormLayout *WidgetUtils::createFormLayout(QWidget *p_parent)
return layout;
}
void WidgetUtils::selectBaseName(QLineEdit *p_lineEdit)
{
auto text = p_lineEdit->text();
int dotIndex = text.lastIndexOf(QLatin1Char('.'));
p_lineEdit->setSelection(0, (dotIndex == -1) ? text.size() : dotIndex);
}

View File

@ -18,6 +18,7 @@ class QListView;
class QMenu;
class QShortcut;
class QFormLayout;
class QLineEdit;
namespace vnotex
{
@ -80,6 +81,9 @@ namespace vnotex
static QFormLayout *createFormLayout(QWidget *p_parent = nullptr);
// Select the base name part of the line edit content.
static void selectBaseName(QLineEdit *p_lineEdit);
private:
static void resizeToHideScrollBar(QScrollArea *p_scroll, bool p_vertical, bool p_horizontal);
};

View File

@ -8,6 +8,7 @@
#include <utils/pathutils.h>
#include "exception.h"
#include "nodeinfowidget.h"
#include <utils/widgetutils.h>
using namespace vnotex;
@ -110,8 +111,7 @@ void NewNoteDialog::initDefaultValues()
{
auto lineEdit = m_infoWidget->getNameLineEdit();
lineEdit->setText(c_defaultNoteName);
int dotIndex = c_defaultNoteName.lastIndexOf('.');
lineEdit->setSelection(0, (dotIndex == -1) ? c_defaultNoteName.size() : dotIndex);
WidgetUtils::selectBaseName(lineEdit);
validateInputs();
}

View File

@ -9,6 +9,7 @@
#include "exception.h"
#include "nodelabelwithupbutton.h"
#include <utils/widgetutils.h>
#include <buffer/filetypehelper.h>
using namespace vnotex;
@ -16,11 +17,9 @@ NodeInfoWidget::NodeInfoWidget(const Node *p_node, QWidget *p_parent)
: QWidget(p_parent),
m_mode(Mode::Edit)
{
setupUI(p_node->getParent());
setupUI(p_node->getParent(), p_node->getType());
setNode(p_node);
setStateAccordingToModeAndNodeType(p_node->getType());
}
NodeInfoWidget::NodeInfoWidget(const Node *p_parentNode,
@ -29,31 +28,42 @@ NodeInfoWidget::NodeInfoWidget(const Node *p_parentNode,
: QWidget(p_parent),
m_mode(Mode::Create)
{
setupUI(p_parentNode);
setStateAccordingToModeAndNodeType(p_typeToCreate);
setupUI(p_parentNode, p_typeToCreate);
}
void NodeInfoWidget::setupUI(const Node *p_parentNode)
void NodeInfoWidget::setupUI(const Node *p_parentNode, Node::Type p_newNodeType)
{
const bool createMode = m_mode == Mode::Create;
const bool isNote = p_newNodeType == Node::Type::File;
m_mainLayout = WidgetUtils::createFormLayout(this);
m_mainLayout->addRow(tr("Notebook:"),
new QLabel(p_parentNode->getNotebook()->getName(), this));
m_parentNodeLabel = new NodeLabelWithUpButton(p_parentNode, this);
m_parentNodeLabel->setReadOnly(!createMode);
connect(m_parentNodeLabel, &NodeLabelWithUpButton::nodeChanged,
this, &NodeInfoWidget::inputEdited);
m_mainLayout->addRow(tr("Location:"), m_parentNodeLabel);
if (createMode && isNote) {
setupFileTypeComboBox(this);
m_mainLayout->addRow(tr("File type:"), m_fileTypeComboBox);
}
setupNameLineEdit(this);
m_mainLayout->addRow(tr("Name:"), m_nameLineEdit);
m_createdDateTimeLabel = new QLabel(this);
m_mainLayout->addRow(tr("Created time:"), m_createdDateTimeLabel);
if (!createMode) {
m_createdDateTimeLabel = new QLabel(this);
m_mainLayout->addRow(tr("Created time:"), m_createdDateTimeLabel);
}
m_modifiedDateTimeLabel = new QLabel(this);
m_mainLayout->addRow(tr("Modified time:"), m_modifiedDateTimeLabel);
if (!createMode && isNote) {
m_modifiedDateTimeLabel = new QLabel(this);
m_mainLayout->addRow(tr("Modified time:"), m_modifiedDateTimeLabel);
}
}
void NodeInfoWidget::setupNameLineEdit(QWidget *p_parent)
@ -63,23 +73,30 @@ void NodeInfoWidget::setupNameLineEdit(QWidget *p_parent)
m_nameLineEdit);
m_nameLineEdit->setValidator(validator);
connect(m_nameLineEdit, &QLineEdit::textEdited,
this, &NodeInfoWidget::inputEdited);
}
this, [this]() {
// Choose the correct file type.
if (m_fileTypeComboBox) {
auto inputName = m_nameLineEdit->text();
QString typeName;
int dotIdx = inputName.lastIndexOf(QLatin1Char('.'));
if (dotIdx != -1) {
auto suffix = inputName.mid(dotIdx + 1);
const auto &fileType = FileTypeHelper::getInst().getFileTypeBySuffix(suffix);
typeName = fileType.m_typeName;
} else {
typeName = FileTypeHelper::getInst().getFileType(FileTypeHelper::Others).m_typeName;
}
void NodeInfoWidget::setStateAccordingToModeAndNodeType(Node::Type p_type)
{
bool createMode = m_mode == Mode::Create;
bool isNote = p_type == Node::Type::File;
int idx = m_fileTypeComboBox->findData(typeName);
if (idx != -1) {
m_fileTypeComboBoxMuted = true;
m_fileTypeComboBox->setCurrentIndex(idx);
m_fileTypeComboBoxMuted = false;
}
}
m_parentNodeLabel->setReadOnly(!createMode);
bool visible = !createMode;
m_createdDateTimeLabel->setVisible(visible);
m_mainLayout->labelForField(m_createdDateTimeLabel)->setVisible(visible);
visible = !createMode && isNote;
m_modifiedDateTimeLabel->setVisible(visible);
m_mainLayout->labelForField(m_modifiedDateTimeLabel)->setVisible(visible);
emit inputEdited();
});
}
QLineEdit *NodeInfoWidget::getNameLineEdit() const
@ -108,6 +125,7 @@ void NodeInfoWidget::setNode(const Node *p_node)
return;
}
Q_ASSERT(m_mode != Mode::Create);
m_node = p_node;
if (m_node) {
Q_ASSERT(getNotebook() == m_node->getNotebook());
@ -120,3 +138,39 @@ void NodeInfoWidget::setNode(const Node *p_node)
m_modifiedDateTimeLabel->setText(modifiedTime);
}
}
void NodeInfoWidget::setupFileTypeComboBox(QWidget *p_parent)
{
m_fileTypeComboBox = WidgetsFactory::createComboBox(p_parent);
const auto &fileTypes = FileTypeHelper::getInst().getAllFileTypes();
for (const auto &ft : fileTypes) {
m_fileTypeComboBox->addItem(ft.m_displayName, ft.m_typeName);
}
connect(m_fileTypeComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, [this]() {
if (m_fileTypeComboBoxMuted) {
return;
}
auto name = m_fileTypeComboBox->currentData().toString();
const auto &fileType = FileTypeHelper::getInst().getFileTypeByName(name);
const auto suffix = fileType.preferredSuffix();
if (!suffix.isEmpty()) {
// Change the suffix.
auto inputName = m_nameLineEdit->text();
QString newName;
int dotIdx = inputName.lastIndexOf(QLatin1Char('.'));
if (dotIdx == -1) {
newName = inputName + QLatin1Char('.') + suffix;
} else if (inputName.mid(dotIdx + 1) != suffix) {
newName = inputName.left(dotIdx + 1) + suffix;
}
if (!newName.isEmpty()) {
m_nameLineEdit->setText(newName);
}
}
WidgetUtils::selectBaseName(m_nameLineEdit);
m_nameLineEdit->setFocus();
});
}

View File

@ -8,6 +8,7 @@
class QLineEdit;
class QLabel;
class QFormLayout;
class QComboBox;
namespace vnotex
{
@ -38,18 +39,20 @@ namespace vnotex
void inputEdited();
private:
void setupUI(const Node *p_parentNode);
void setupUI(const Node *p_parentNode, Node::Type p_newNodeType);
void setupFileTypeComboBox(QWidget *p_parent);
void setupNameLineEdit(QWidget *p_parent);
void setStateAccordingToModeAndNodeType(Node::Type p_type);
void setNode(const Node *p_node);
Mode m_mode;
QFormLayout *m_mainLayout = nullptr;
QComboBox *m_fileTypeComboBox = nullptr;
QLineEdit *m_nameLineEdit = nullptr;
NodeLabelWithUpButton *m_parentNodeLabel = nullptr;
@ -59,6 +62,8 @@ namespace vnotex
QLabel *m_modifiedDateTimeLabel = nullptr;
const Node *m_node = nullptr;
bool m_fileTypeComboBoxMuted = false;
};
} // ns vnotex

View File

@ -27,9 +27,9 @@ void NodeLabelWithUpButton::setupUI()
auto iconFile = VNoteX::getInst().getThemeMgr().getIconFile("up_parent_node.svg");
m_upButton = new QPushButton(IconUtils::fetchIconWithDisabledState(iconFile),
"",
tr("Up"),
this);
m_upButton->setToolTip(tr("Up"));
m_upButton->setToolTip(tr("Create note under an upper level node"));
connect(m_upButton, &QPushButton::clicked,
this, [this]() {
if (!m_node->isRoot()) {

View File

@ -51,6 +51,10 @@ void MarkdownEditorPage::loadInternal()
m_sectionNumberComboBox->setCurrentIndex(idx);
m_sectionNumberBaseLevelSpinBox->setValue(markdownConfig.getSectionNumberBaseLevel());
idx = m_sectionNumberStyleComboBox->findData(static_cast<int>(markdownConfig.getSectionNumberStyle()));
Q_ASSERT(idx != -1);
m_sectionNumberStyleComboBox->setCurrentIndex(idx);
}
m_constrainImageWidthCheckBox->setChecked(markdownConfig.getConstrainImageWidthEnabled());
@ -83,6 +87,11 @@ void MarkdownEditorPage::saveInternal()
if (m_sectionNumberBaseLevelSpinBox->isEnabled()) {
markdownConfig.setSectionNumberBaseLevel(m_sectionNumberBaseLevelSpinBox->value());
}
if (m_sectionNumberStyleComboBox->isEnabled()) {
auto style = m_sectionNumberStyleComboBox->currentData().toInt();
markdownConfig.setSectionNumberStyle(static_cast<MarkdownEditorConfig::SectionNumberStyle>(style));
}
}
markdownConfig.setConstrainImageWidthEnabled(m_constrainImageWidthCheckBox->isChecked());
@ -229,11 +238,9 @@ QGroupBox *MarkdownEditorPage::setupGeneralGroup()
m_sectionNumberComboBox = WidgetsFactory::createComboBox(this);
m_sectionNumberComboBox->setToolTip(tr("Section number mode"));
m_sectionNumberComboBox->addItem(tr("None"), (int)MarkdownEditorConfig::SectionNumberMode::None);
m_sectionNumberComboBox->addItem(tr("Read"), (int)MarkdownEditorConfig::SectionNumberMode::Read);
m_sectionNumberComboBox->addItem(tr("Edit"), (int)MarkdownEditorConfig::SectionNumberMode::Edit);
sectionLayout->addWidget(m_sectionNumberComboBox);
connect(m_sectionNumberComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &MarkdownEditorPage::pageIsChanged);
@ -242,13 +249,22 @@ QGroupBox *MarkdownEditorPage::setupGeneralGroup()
m_sectionNumberBaseLevelSpinBox->setToolTip(tr("Base level to start section numbering in edit mode"));
m_sectionNumberBaseLevelSpinBox->setRange(1, 6);
m_sectionNumberBaseLevelSpinBox->setSingleStep(1);
sectionLayout->addWidget(m_sectionNumberBaseLevelSpinBox);
connect(m_sectionNumberBaseLevelSpinBox, QOverload<int>::of(&QSpinBox::valueChanged),
this, &MarkdownEditorPage::pageIsChanged);
m_sectionNumberStyleComboBox = WidgetsFactory::createComboBox(this);
m_sectionNumberStyleComboBox->setToolTip(tr("Section number style"));
m_sectionNumberStyleComboBox->addItem(tr("1.1."), (int)MarkdownEditorConfig::SectionNumberStyle::DigDotDigDot);
m_sectionNumberStyleComboBox->addItem(tr("1.1"), (int)MarkdownEditorConfig::SectionNumberStyle::DigDotDig);
sectionLayout->addWidget(m_sectionNumberStyleComboBox);
connect(m_sectionNumberStyleComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &MarkdownEditorPage::pageIsChanged);
connect(m_sectionNumberComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, [this](int p_index) {
m_sectionNumberBaseLevelSpinBox->setEnabled(p_index == MarkdownEditorConfig::SectionNumberMode::Edit);
m_sectionNumberStyleComboBox->setEnabled(p_index == MarkdownEditorConfig::SectionNumberMode::Edit);
});
const QString label(tr("Section number:"));

View File

@ -54,6 +54,8 @@ namespace vnotex
QComboBox *m_sectionNumberComboBox = nullptr;
QSpinBox *m_sectionNumberBaseLevelSpinBox = nullptr;
QComboBox *m_sectionNumberStyleComboBox = nullptr;
};
}

View File

@ -755,7 +755,6 @@ void MarkdownEditor::updateHeadings(const QVector<vte::peg::ElementRegion> &p_he
// Assume that each block contains only one line.
// Only support # syntax for now.
auto doc = document();
QRegExp headerReg(vte::MarkdownUtils::c_headerRegExp);
for (auto const &reg : p_headerRegions) {
auto block = doc->findBlock(reg.m_startPos);
if (!block.isValid()) {
@ -766,11 +765,11 @@ void MarkdownEditor::updateHeadings(const QVector<vte::peg::ElementRegion> &p_he
qWarning() << "header accross multiple blocks, starting from block" << block.blockNumber() << block.text();
}
if (headerReg.exactMatch(block.text())) {
const int level = headerReg.cap(1).length();
Heading heading(headerReg.cap(2).trimmed(),
level,
headerReg.cap(3),
auto match = vte::MarkdownUtils::matchHeader(block.text());
if (match.m_matched) {
Heading heading(match.m_header,
match.m_level,
match.m_sequence,
block.blockNumber());
headings.append(heading);
}
@ -1097,10 +1096,9 @@ static void increaseSectionNumber(QVector<int> &p_sectionNumber, int p_level, in
}
}
static QString joinSectionNumberStr(const QVector<int> &p_sectionNumber)
static QString joinSectionNumberStr(const QVector<int> &p_sectionNumber, bool p_endingDot)
{
QString res;
// TODO: make it configurable? 1.1 or 1.1.?
for (auto sec : p_sectionNumber) {
if (sec != 0) {
if (res.isEmpty()) {
@ -1115,28 +1113,41 @@ static QString joinSectionNumberStr(const QVector<int> &p_sectionNumber)
}
}
return res;
if (p_endingDot && !res.isEmpty()) {
return res + '.';
} else {
return res;
}
}
static bool updateHeadingSectionNumber(QTextCursor &p_cursor,
const QTextBlock &p_block,
QRegExp &p_headingReg,
QRegExp &p_prefixReg,
const QString &p_sectionNumber)
const QString &p_sectionNumber,
bool p_endingDot)
{
if (!p_block.isValid()) {
return false;
}
QString text = p_block.text();
bool matched = p_headingReg.exactMatch(text);
Q_ASSERT(matched);
auto match = vte::MarkdownUtils::matchHeader(text);
Q_ASSERT(match.m_matched);
matched = p_prefixReg.exactMatch(text);
Q_ASSERT(matched);
bool isSequence = false;
if (!match.m_sequence.isEmpty()) {
// Check if this sequence is the real sequence matching current style.
if (match.m_sequence.endsWith('.')) {
isSequence = p_endingDot;
} else {
isSequence = !p_endingDot;
}
}
int start = p_headingReg.cap(1).length() + 1;
int end = p_prefixReg.cap(1).length();
int start = match.m_level + 1;
int end = match.m_level + match.m_spacesAfterMarker;
if (isSequence) {
end += match.m_sequence.size() + match.m_spacesAfterSequence;
}
Q_ASSERT(start <= end);
@ -1162,20 +1173,18 @@ bool MarkdownEditor::updateSectionNumber(const QVector<Heading> &p_headings)
}
bool changed = false;
bool endingDot = m_config.getSectionNumberStyle() == MarkdownEditorConfig::SectionNumberStyle::DigDotDigDot;
auto doc = document();
QRegExp headerReg(vte::MarkdownUtils::c_headerRegExp);
QRegExp prefixReg(vte::MarkdownUtils::c_headerPrefixRegExp);
QTextCursor cursor(doc);
cursor.beginEditBlock();
for (const auto &heading : p_headings) {
increaseSectionNumber(sectionNumber, heading.m_level, baseLevel);
auto sectionStr = m_sectionNumberEnabled ? joinSectionNumberStr(sectionNumber) : QString();
auto sectionStr = m_sectionNumberEnabled ? joinSectionNumberStr(sectionNumber, endingDot) : QString();
if (heading.m_blockNumber > -1 && sectionStr != heading.m_sectionNumber) {
if (updateHeadingSectionNumber(cursor,
doc->findBlockByNumber(heading.m_blockNumber),
headerReg,
prefixReg,
sectionStr)) {
sectionStr,
endingDot)) {
changed = true;
}
}

View File

@ -251,7 +251,8 @@ void MarkdownViewWindow::handleBufferChangedInternal()
void MarkdownViewWindow::setupToolBar()
{
auto toolBar = new QToolBar(this);
auto toolBar = createToolBar(this);
const auto &editorConfig = ConfigMgr::getInst().getEditorConfig();
const int iconSize = editorConfig.getToolBarIconSize();
toolBar->setIconSize(QSize(iconSize, iconSize));

View File

@ -51,6 +51,7 @@ void OutlineViewer::setupUI(const QString &p_title)
{
auto mainLayout = new QVBoxLayout(this);
mainLayout->setContentsMargins(0, 0, 0, 0);
mainLayout->setSpacing(0);
{
auto titleBar = setupTitleBar(p_title, this);

View File

@ -13,3 +13,5 @@ const char *PropertyDefs::s_dialogCentralWidget = "DialogCentralWidget";
const char *PropertyDefs::s_viewSplitCornerWidget = "ViewSplitCornerWidget";
const char *PropertyDefs::s_state = "State";
const char *PropertyDefs::s_viewWindowToolBar = "ViewWindowToolBar";

View File

@ -19,6 +19,8 @@ namespace vnotex
static const char *s_viewSplitCornerWidget;
static const char *s_viewWindowToolBar;
// Values: info/warning/error.
static const char *s_state;
};

View File

@ -55,7 +55,7 @@ void TextViewWindow::setupUI()
void TextViewWindow::setupToolBar()
{
auto toolBar = new QToolBar(this);
auto toolBar = createToolBar(this);
const auto &editorConfig = ConfigMgr::getInst().getEditorConfig();
const int iconSize = editorConfig.getToolBarIconSize();
toolBar->setIconSize(QSize(iconSize, iconSize));

View File

@ -32,6 +32,7 @@
#include "exception.h"
#include "findandreplacewidget.h"
#include "editors/statuswidget.h"
#include "propertydefs.h"
using namespace vnotex;
@ -106,14 +107,17 @@ ViewWindow::~ViewWindow()
void ViewWindow::setupUI()
{
m_mainLayout = new QVBoxLayout(this);
m_mainLayout->setSpacing(0);
m_mainLayout->setContentsMargins(0, 0, 0, 0);
m_topLayout = new QVBoxLayout();
m_topLayout->setContentsMargins(0, 0, 0, 0);
m_topLayout->setSpacing(0);
m_mainLayout->addLayout(m_topLayout, 0);
m_bottomLayout = new QVBoxLayout();
m_bottomLayout->setContentsMargins(0, 0, 0, 0);
m_bottomLayout->setSpacing(0);
m_mainLayout->addLayout(m_bottomLayout, 0);
}
@ -1073,3 +1077,10 @@ void ViewWindow::read(bool p_save)
}
setFocus();
}
QToolBar *ViewWindow::createToolBar(QWidget *p_parent)
{
auto toolBar = new QToolBar(p_parent);
toolBar->setProperty(PropertyDefs::s_viewWindowToolBar, true);
return toolBar;
}

View File

@ -11,6 +11,7 @@
class QVBoxLayout;
class QTimer;
class QToolBar;
namespace vnotex
{
@ -218,6 +219,8 @@ namespace vnotex
static ViewWindow::Mode modeFromOpenParameters(const FileOpenParameters &p_paras);
static QToolBar *createToolBar(QWidget *p_parent = nullptr);
// The revision of the buffer of the last sync content.
int m_bufferRevision = 0;