diff --git a/VNote.pro b/VNote.pro index 36cae7fa..8c1fe8af 100644 --- a/VNote.pro +++ b/VNote.pro @@ -17,10 +17,10 @@ SOURCES += main.cpp\ vdirectorytree.cpp \ vnote.cpp \ vnotebook.cpp \ - vnewdirdialog.cpp \ + dialog/vnewdirdialog.cpp \ vconfigmanager.cpp \ vfilelist.cpp \ - vnewfiledialog.cpp \ + dialog/vnewfiledialog.cpp \ vtabwidget.cpp \ vedit.cpp \ veditor.cpp \ @@ -31,16 +31,17 @@ SOURCES += main.cpp\ utils/peg-highlight/pmh_parser.c \ hgmarkdownhighlighter.cpp \ vstyleparser.cpp \ - utils/peg-highlight/pmh_styleparser.c + utils/peg-highlight/pmh_styleparser.c \ + dialog/vnewnotebookdialog.cpp HEADERS += vmainwindow.h \ vdirectorytree.h \ vnote.h \ vnotebook.h \ - vnewdirdialog.h \ + dialog/vnewdirdialog.h \ vconfigmanager.h \ vfilelist.h \ - vnewfiledialog.h \ + dialog/vnewfiledialog.h \ vtabwidget.h \ vedit.h \ veditor.h \ @@ -53,7 +54,8 @@ HEADERS += vmainwindow.h \ hgmarkdownhighlighter.h \ utils/peg-highlight/pmh_definitions.h \ vstyleparser.h \ - utils/peg-highlight/pmh_styleparser.h + utils/peg-highlight/pmh_styleparser.h \ + dialog/vnewnotebookdialog.h RESOURCES += \ vnote.qrc diff --git a/vnewdirdialog.cpp b/dialog/vnewdirdialog.cpp similarity index 100% rename from vnewdirdialog.cpp rename to dialog/vnewdirdialog.cpp diff --git a/vnewdirdialog.h b/dialog/vnewdirdialog.h similarity index 100% rename from vnewdirdialog.h rename to dialog/vnewdirdialog.h diff --git a/vnewfiledialog.cpp b/dialog/vnewfiledialog.cpp similarity index 100% rename from vnewfiledialog.cpp rename to dialog/vnewfiledialog.cpp diff --git a/vnewfiledialog.h b/dialog/vnewfiledialog.h similarity index 100% rename from vnewfiledialog.h rename to dialog/vnewfiledialog.h diff --git a/dialog/vnewnotebookdialog.cpp b/dialog/vnewnotebookdialog.cpp new file mode 100644 index 00000000..c7498c7d --- /dev/null +++ b/dialog/vnewnotebookdialog.cpp @@ -0,0 +1,86 @@ +#include +#include "vnewnotebookdialog.h" + +VNewNotebookDialog::VNewNotebookDialog(const QString &title, const QString &info, + const QString &defaultName, const QString &defaultPath, + QWidget *parent) + : QDialog(parent), title(title), info(info), defaultName(defaultName), defaultPath(defaultPath), + infoLabel(NULL) +{ + setupUI(); + + connect(nameEdit, &QLineEdit::textChanged, this, &VNewNotebookDialog::enableOkButton); + connect(pathEdit, &QLineEdit::textChanged, this, &VNewNotebookDialog::enableOkButton); + connect(browseBtn, &QPushButton::clicked, this, &VNewNotebookDialog::handleBrowseBtnClicked); + connect(okBtn, &QPushButton::clicked, this, &VNewNotebookDialog::accept); + connect(cancelBtn, &QPushButton::clicked, this, &VNewNotebookDialog::reject); + + enableOkButton(); +} + +void VNewNotebookDialog::setupUI() +{ + if (!info.isEmpty()) { + infoLabel = new QLabel(info); + } + nameLabel = new QLabel(tr("&Name")); + nameEdit = new QLineEdit(defaultName); + nameEdit->selectAll(); + nameLabel->setBuddy(nameEdit); + + QLabel *pathLabel = new QLabel(tr("&Path")); + pathEdit = new QLineEdit(defaultPath); + pathLabel->setBuddy(pathEdit); + browseBtn = new QPushButton(tr("&Browse")); + + QHBoxLayout *pathLayout = new QHBoxLayout(); + pathLayout->addWidget(pathEdit); + pathLayout->addWidget(browseBtn); + + okBtn = new QPushButton(tr("&OK")); + okBtn->setDefault(true); + cancelBtn = new QPushButton(tr("&Cancel")); + + QVBoxLayout *topLayout = new QVBoxLayout(); + if (infoLabel) { + topLayout->addWidget(infoLabel); + } + topLayout->addWidget(nameLabel); + topLayout->addWidget(nameEdit); + topLayout->addWidget(pathLabel); + topLayout->addLayout(pathLayout); + + QHBoxLayout *btmLayout = new QHBoxLayout(); + btmLayout->addStretch(); + btmLayout->addWidget(okBtn); + btmLayout->addWidget(cancelBtn); + + QVBoxLayout *mainLayout = new QVBoxLayout(); + mainLayout->addLayout(topLayout); + mainLayout->addLayout(btmLayout); + setLayout(mainLayout); + + setWindowTitle(title); +} + +void VNewNotebookDialog::enableOkButton() +{ + okBtn->setEnabled(!pathEdit->text().isEmpty() && !nameEdit->text().isEmpty()); +} + +QString VNewNotebookDialog::getNameInput() const +{ + return nameEdit->text(); +} + +QString VNewNotebookDialog::getPathInput() const +{ + return pathEdit->text(); +} + +void VNewNotebookDialog::handleBrowseBtnClicked() +{ + QString dirPath = QFileDialog::getExistingDirectory(this, tr("Select a directory as the path of the notebook"), + "", QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); + pathEdit->setText(dirPath); +} diff --git a/dialog/vnewnotebookdialog.h b/dialog/vnewnotebookdialog.h new file mode 100644 index 00000000..998c1bf9 --- /dev/null +++ b/dialog/vnewnotebookdialog.h @@ -0,0 +1,41 @@ +#ifndef VNEWNOTEBOOKDIALOG_H +#define VNEWNOTEBOOKDIALOG_H + +#include + +class QLabel; +class QLineEdit; +class QPushButton; +class QString; + +class VNewNotebookDialog : public QDialog +{ + Q_OBJECT +public: + VNewNotebookDialog(const QString &title, const QString &info, const QString &defaultName, + const QString &defaultPath, QWidget *parent = 0); + QString getNameInput() const; + QString getPathInput() const; + +private slots: + void enableOkButton(); + void handleBrowseBtnClicked(); + +private: + void setupUI(); + + QLabel *infoLabel; + QLabel *nameLabel; + QLineEdit *nameEdit; + QLineEdit *pathEdit; + QPushButton *browseBtn; + QPushButton *okBtn; + QPushButton *cancelBtn; + + QString title; + QString defaultName; + QString info; + QString defaultPath; +}; + +#endif // VNEWNOTEBOOKDIALOG_H diff --git a/resources/icons/create_notebook.png b/resources/icons/create_notebook.png new file mode 100755 index 00000000..a76887a0 Binary files /dev/null and b/resources/icons/create_notebook.png differ diff --git a/resources/icons/delete_notebook.png b/resources/icons/delete_notebook.png new file mode 100755 index 00000000..67337156 Binary files /dev/null and b/resources/icons/delete_notebook.png differ diff --git a/resources/icons/notebook_info.png b/resources/icons/notebook_info.png new file mode 100755 index 00000000..8e03190a Binary files /dev/null and b/resources/icons/notebook_info.png differ diff --git a/vdirectorytree.cpp b/vdirectorytree.cpp index d87d46e6..a2071270 100644 --- a/vdirectorytree.cpp +++ b/vdirectorytree.cpp @@ -1,6 +1,6 @@ #include #include "vdirectorytree.h" -#include "vnewdirdialog.h" +#include "dialog/vnewdirdialog.h" #include "vconfigmanager.h" VDirectoryTree::VDirectoryTree(QWidget *parent) diff --git a/vfilelist.cpp b/vfilelist.cpp index 7a8e8ecd..d9b02e71 100644 --- a/vfilelist.cpp +++ b/vfilelist.cpp @@ -2,7 +2,7 @@ #include #include "vfilelist.h" #include "vconfigmanager.h" -#include "vnewfiledialog.h" +#include "dialog/vnewfiledialog.h" VFileList::VFileList(QWidget *parent) : QListWidget(parent) diff --git a/vmainwindow.cpp b/vmainwindow.cpp index d2d650d5..d4db6eba 100644 --- a/vmainwindow.cpp +++ b/vmainwindow.cpp @@ -5,17 +5,21 @@ #include "vfilelist.h" #include "vtabwidget.h" #include "vconfigmanager.h" +#include "dialog/vnewnotebookdialog.h" extern VConfigManager vconfig; VMainWindow::VMainWindow(QWidget *parent) : QMainWindow(parent) { + // Must be called before those who uses VConfigManager vnote = new VNote(); setupUI(); initActions(); initToolBar(); - updateNotebookComboBox(); + initMenuBar(); + + updateNotebookComboBox(vnote->getNotebooks()); } VMainWindow::~VMainWindow() @@ -28,12 +32,24 @@ void VMainWindow::setupUI() // Notebook directory browser tree notebookLabel = new QLabel(tr("Notebook")); directoryLabel = new QLabel(tr("Directory")); + newNotebookBtn = new QPushButton(QIcon(":/resources/icons/create_notebook.png"), ""); + newNotebookBtn->setToolTip(tr("Create a new notebook")); + deleteNotebookBtn = new QPushButton(QIcon(":/resources/icons/delete_notebook.png"), ""); + deleteNotebookBtn->setToolTip(tr("Delete current notebook")); + notebookInfoBtn = new QPushButton(QIcon(":/resources/icons/notebook_info.png"), ""); + notebookInfoBtn->setToolTip(tr("View and edit current notebook's information")); notebookComboBox = new QComboBox(); notebookComboBox->setSizeAdjustPolicy(QComboBox::AdjustToContents); directoryTree = new VDirectoryTree(); + QHBoxLayout *nbBtnLayout = new QHBoxLayout; + nbBtnLayout->addWidget(notebookLabel); + nbBtnLayout->addStretch(); + nbBtnLayout->addWidget(newNotebookBtn); + nbBtnLayout->addWidget(deleteNotebookBtn); + nbBtnLayout->addWidget(notebookInfoBtn); QVBoxLayout *nbLayout = new QVBoxLayout; - nbLayout->addWidget(notebookLabel); + nbLayout->addLayout(nbBtnLayout); nbLayout->addWidget(notebookComboBox); nbLayout->addWidget(directoryLabel); nbLayout->addWidget(directoryTree); @@ -68,6 +84,10 @@ void VMainWindow::setupUI() fileList, &VFileList::setDirectory); connect(fileList, &VFileList::fileClicked, tabs, &VTabWidget::openFile); + connect(newNotebookBtn, &QPushButton::clicked, + this, &VMainWindow::onNewNotebookBtnClicked); + connect(vnote, &VNote::notebooksChanged, + this, &VMainWindow::updateNotebookComboBox); setCentralWidget(mainSplitter); // Create and show the status bar @@ -94,17 +114,27 @@ void VMainWindow::initActions() void VMainWindow::initToolBar() { - fileToolBar = addToolBar(tr("Note")); + QToolBar *fileToolBar = addToolBar(tr("Note")); fileToolBar->setMovable(false); fileToolBar->addAction(editNoteAct); fileToolBar->addAction(readNoteAct); fileToolBar->addAction(saveNoteAct); } -void VMainWindow::updateNotebookComboBox() +void VMainWindow::initMenuBar() { - const QVector ¬ebooks = vnote->getNotebooks(); + QMenu *fileMenu = menuBar()->addMenu(tr("&File")); + QMenu *helpMenu = menuBar()->addMenu(tr("&Help")); + // To be implemented +} + +void VMainWindow::updateNotebookComboBox(const QVector ¬ebooks) +{ + // Clearing and inserting items will emit the signal which corrupt the vconfig's + // current index. We save it first and then set the combobox index to the + // right one to resrote it. + int curIndex = vconfig.getCurNotebookIndex(); notebookComboBox->clear(); if (notebooks.isEmpty()) { return; @@ -114,20 +144,53 @@ void VMainWindow::updateNotebookComboBox() } qDebug() << "update notebook combobox with" << notebookComboBox->count() - << "items"; - notebookComboBox->setCurrentIndex(vconfig.getCurNotebookIndex()); + << "items, current notebook" << curIndex; + notebookComboBox->setCurrentIndex(curIndex); } void VMainWindow::setCurNotebookIndex(int index) { Q_ASSERT(index < vnote->getNotebooks().size()); - qDebug() << "set current notebook index:" << index; - vconfig.setCurNotebookIndex(index); - // Update directoryTree QString treePath; if (index > -1) { + vconfig.setCurNotebookIndex(index); treePath = vnote->getNotebooks()[index].getPath(); } emit curNotebookIndexChanged(treePath); } + +void VMainWindow::onNewNotebookBtnClicked() +{ + qDebug() << "request to create a notebook"; + QString info; + QString defaultName("new_notebook"); + QString defaultPath; + do { + VNewNotebookDialog dialog(tr("Create a new notebook"), info, defaultName, + defaultPath, this); + if (dialog.exec() == QDialog::Accepted) { + QString name = dialog.getNameInput(); + QString path = dialog.getPathInput(); + if (isConflictWithExistingNotebooks(name, path)) { + info = "Name already exists or the path already has a notebook."; + defaultName = name; + defaultPath = path; + continue; + } + vnote->createNotebook(name, path); + } + break; + } while (true); +} + +bool VMainWindow::isConflictWithExistingNotebooks(const QString &name, const QString &path) +{ + const QVector ¬ebooks = vnote->getNotebooks(); + for (int i = 0; i < notebooks.size(); ++i) { + if (notebooks[i].getName() == name || notebooks[i].getPath() == path) { + return true; + } + } + return false; +} diff --git a/vmainwindow.h b/vmainwindow.h index 3145b83d..5fe44cd2 100644 --- a/vmainwindow.h +++ b/vmainwindow.h @@ -14,6 +14,8 @@ class VNote; class VFileList; class VTabWidget; class QAction; +class QPushButton; +class VNotebook; class VMainWindow : public QMainWindow { @@ -26,26 +28,31 @@ public: private slots: // Change current notebook index and update the directory tree void setCurNotebookIndex(int index); + // Create a notebook + void onNewNotebookBtnClicked(); + void updateNotebookComboBox(const QVector ¬ebooks); signals: void curNotebookIndexChanged(const QString &path); private: void setupUI(); - // Update notebookComboBox according to vnote - void updateNotebookComboBox(); void initActions(); void initToolBar(); + void initMenuBar(); + bool isConflictWithExistingNotebooks(const QString &name, const QString &path); QLabel *notebookLabel; QLabel *directoryLabel; QComboBox *notebookComboBox; + QPushButton *newNotebookBtn; + QPushButton *deleteNotebookBtn; + QPushButton *notebookInfoBtn; VDirectoryTree *directoryTree; VFileList *fileList; VTabWidget *tabs; QSplitter *mainSplitter; VNote *vnote; - QToolBar *fileToolBar; // Actions QAction *editNoteAct; diff --git a/vnote.cpp b/vnote.cpp index 96b533fb..b9b187f7 100644 --- a/vnote.cpp +++ b/vnote.cpp @@ -1,5 +1,7 @@ #include #include +#include +#include #include "vnote.h" #include "utils/vutils.h" #include "vconfigmanager.h" @@ -8,11 +10,12 @@ VConfigManager vconfig; QString VNote::templateHtml; -VNote::VNote() +VNote::VNote() : QObject() { vconfig.initialize(); decorateTemplate(); notebooks = vconfig.getNotebooks(); + emit notebooksChanged(notebooks); } void VNote::decorateTemplate() @@ -25,3 +28,25 @@ const QVector& VNote::getNotebooks() { return notebooks; } + +void VNote::createNotebook(const QString &name, const QString &path) +{ + // Create a directory config file in @path + QJsonObject configJson; + configJson["version"] = "1"; + configJson["name"] = name; + configJson["sub_directories"] = QJsonArray(); + configJson["files"] = QJsonArray(); + if (!vconfig.writeDirectoryConfig(path, configJson)) { + return; + } + + // Update notebooks settings + notebooks.prepend(VNotebook(name, path)); + vconfig.setNotebooks(notebooks); + + // Set current index to the new notebook + vconfig.setCurNotebookIndex(0); + + emit notebooksChanged(notebooks); +} diff --git a/vnote.h b/vnote.h index ebb371b5..9d2b8898 100644 --- a/vnote.h +++ b/vnote.h @@ -5,10 +5,12 @@ #include #include #include +#include #include "vnotebook.h" -class VNote +class VNote : public QObject { + Q_OBJECT public: VNote(); @@ -18,6 +20,11 @@ public: static QString templateHtml; + void createNotebook(const QString &name, const QString &path); + +signals: + void notebooksChanged(const QVector ¬ebooks); + private: QVector notebooks; }; diff --git a/vnote.qrc b/vnote.qrc index 5148a7df..33c02972 100644 --- a/vnote.qrc +++ b/vnote.qrc @@ -36,5 +36,8 @@ resources/styles/solarized-light.mdhl resources/styles/solarized-dark.mdhl resources/vnote.ini + resources/icons/create_notebook.png + resources/icons/delete_notebook.png + resources/icons/notebook_info.png