add VFileListPanel as a wrapper of VFileList

Signed-off-by: Le Tan <tamlokveer@gmail.com>
This commit is contained in:
Le Tan 2016-10-25 22:27:09 +08:00
parent 5409ce9769
commit 1f80fb8583
15 changed files with 442 additions and 23 deletions

View File

@ -0,0 +1,60 @@
#include <QtWidgets>
#include "vfileinfodialog.h"
VFileInfoDialog::VFileInfoDialog(const QString &title, const QString &info,
const QString &defaultName,
QWidget *parent)
: QDialog(parent), infoLabel(NULL), title(title), info(info), defaultName(defaultName)
{
setupUI();
connect(nameEdit, &QLineEdit::textChanged, this, &VFileInfoDialog::enableOkButton);
connect(okBtn, &QPushButton::clicked, this, &VFileInfoDialog::accept);
connect(cancelBtn, &QPushButton::clicked, this, &VFileInfoDialog::reject);
enableOkButton();
}
void VFileInfoDialog::setupUI()
{
if (!info.isEmpty()) {
infoLabel = new QLabel(info);
}
nameLabel = new QLabel(tr("&Name"));
nameEdit = new QLineEdit(defaultName);
nameEdit->selectAll();
nameLabel->setBuddy(nameEdit);
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);
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 VFileInfoDialog::enableOkButton()
{
okBtn->setEnabled(!nameEdit->text().isEmpty());
}
QString VFileInfoDialog::getNameInput() const
{
return nameEdit->text();
}

View File

@ -0,0 +1,36 @@
#ifndef VFILEINFODIALOG_H
#define VFILEINFODIALOG_H
#include <QDialog>
class QLabel;
class QLineEdit;
class QPushButton;
class QString;
class VFileInfoDialog : public QDialog
{
Q_OBJECT
public:
VFileInfoDialog(const QString &title, const QString &info, const QString &defaultName,
QWidget *parent = 0);
QString getNameInput() const;
private slots:
void enableOkButton();
private:
void setupUI();
QLabel *infoLabel;
QLabel *nameLabel;
QLineEdit *nameEdit;
QPushButton *okBtn;
QPushButton *cancelBtn;
QString title;
QString info;
QString defaultName;
};
#endif // VFILEINFODIALOG_H

Binary file not shown.

After

Width:  |  Height:  |  Size: 223 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 B

BIN
src/resources/icons/note_info.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -35,7 +35,9 @@ SOURCES += main.cpp\
dialog/vnewnotebookdialog.cpp \
vmarkdownconverter.cpp \
dialog/vnotebookinfodialog.cpp \
dialog/vdirinfodialog.cpp
dialog/vdirinfodialog.cpp \
vfilelistpanel.cpp \
dialog/vfileinfodialog.cpp
HEADERS += vmainwindow.h \
vdirectorytree.h \
@ -61,7 +63,9 @@ HEADERS += vmainwindow.h \
dialog/vnewnotebookdialog.h \
vmarkdownconverter.h \
dialog/vnotebookinfodialog.h \
dialog/vdirinfodialog.h
dialog/vdirinfodialog.h \
vfilelistpanel.h \
dialog/vfileinfodialog.h
RESOURCES += \
vnote.qrc

View File

@ -175,9 +175,20 @@ bool VEditor::saveFile()
if (!isEditMode || !noteFile->modifiable || !textEditor->isModified()) {
return true;
}
// Make sure the file already exists. Temporary deal with cases when user delete or move
// a file.
QString filePath = QDir(noteFile->basePath).filePath(noteFile->fileName);
if (!QFile(filePath).exists()) {
qWarning() << "error:" << filePath << "being written has been removed";
QMessageBox msgBox(QMessageBox::Warning, tr("Fail to save to file"),
QString("%1 being written has been removed.").arg(filePath),
QMessageBox::Ok, this);
msgBox.setDefaultButton(QMessageBox::Ok);
msgBox.exec();
return false;
}
textEditor->saveFile();
bool ret = VUtils::writeFileToDisk(QDir(noteFile->basePath).filePath(noteFile->fileName),
noteFile->content);
bool ret = VUtils::writeFileToDisk(filePath, 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."),

View File

@ -55,7 +55,6 @@ void VFileList::setDirectory(QJsonObject dirJson)
void VFileList::clearDirectoryInfo()
{
notebook = relativePath = rootPath = "";
clear();
}
void VFileList::updateFileList()
@ -357,6 +356,7 @@ void VFileList::handleNotebookRenamed(const QVector<VNotebook> &notebooks,
}
}
// FIXME: when @oldRelativePath is part of relativePath, we also need to update relativePath partialy
void VFileList::handleDirectoryRenamed(const QString &notebook,
const QString &oldRelativePath, const QString &newRelativePath)
{

View File

@ -23,8 +23,6 @@ signals:
void fileCreated(QJsonObject fileJson);
private slots:
void newFile();
void deleteFile();
void contextMenuRequested(QPoint pos);
void handleItemClicked(QListWidgetItem *currentItem);
@ -34,6 +32,8 @@ public slots:
const QString &newName);
void handleDirectoryRenamed(const QString &notebook, const QString &oldRelativePath,
const QString &newRelativePath);
void newFile();
void deleteFile();
private:
void updateFileList();

232
src/vfilelistpanel.cpp Normal file
View File

@ -0,0 +1,232 @@
#include <QtWidgets>
#include "vfilelistpanel.h"
#include "vfilelist.h"
#include "dialog/vfileinfodialog.h"
#include "vnotebook.h"
#include "vnote.h"
#include "vconfigmanager.h"
VFileListPanel::VFileListPanel(VNote *vnote, QWidget *parent)
: QWidget(parent), vnote(vnote)
{
setupUI();
}
void VFileListPanel::setupUI()
{
newFileBtn = new QPushButton(QIcon(":/resources/icons/create_note.png"), "");
newFileBtn->setToolTip(tr("Create a new note"));
deleteFileBtn = new QPushButton(QIcon(":/resources/icons/delete_note.png"), "");
deleteFileBtn->setToolTip(tr("Delete current note"));
fileInfoBtn = new QPushButton(QIcon(":/resources/icons/note_info.png"), "");
fileInfoBtn->setToolTip(tr("View and edit current note's information"));
fileList = new VFileList(vnote);
QHBoxLayout *topLayout = new QHBoxLayout;
topLayout->addStretch();
topLayout->addWidget(newFileBtn);
topLayout->addWidget(deleteFileBtn);
topLayout->addWidget(fileInfoBtn);
QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->addLayout(topLayout);
mainLayout->addWidget(fileList);
// Signals
connect(fileList, &VFileList::fileClicked,
this, &VFileListPanel::fileClicked);
connect(fileList, &VFileList::fileDeleted,
this, &VFileListPanel::fileDeleted);
connect(fileList, &VFileList::fileCreated,
this, &VFileListPanel::fileCreated);
connect(newFileBtn, &QPushButton::clicked,
this, &VFileListPanel::onNewFileBtnClicked);
connect(deleteFileBtn, &QPushButton::clicked,
this, &VFileListPanel::onDeleteFileBtnClicked);
connect(fileInfoBtn, &QPushButton::clicked,
this, &VFileListPanel::onFileInfoBtnClicked);
setLayout(mainLayout);
}
void VFileListPanel::setDirectory(QJsonObject dirJson)
{
if (dirJson.isEmpty()) {
clearDirectoryInfo();
fileList->setDirectory(dirJson);
return;
}
notebook = dirJson["notebook"].toString();
relativePath = dirJson["relative_path"].toString();
rootPath = "";
const QVector<VNotebook> &notebooks = vnote->getNotebooks();
for (int i = 0; i < notebooks.size(); ++i) {
if (notebooks[i].getName() == notebook) {
rootPath = notebooks[i].getPath();
break;
}
}
Q_ASSERT(!rootPath.isEmpty());
fileList->setDirectory(dirJson);
}
void VFileListPanel::clearDirectoryInfo()
{
notebook = relativePath = rootPath = "";
fileList->clear();
}
void VFileListPanel::handleNotebookRenamed(const QVector<VNotebook> &notebooks,
const QString &oldName, const QString &newName)
{
if (oldName == notebook) {
// Update treePath (though treePath actually will not be changed)
notebook = newName;
rootPath.clear();
const QVector<VNotebook> &notebooks = vnote->getNotebooks();
for (int i = 0; i < notebooks.size(); ++i) {
if (notebooks[i].getName() == notebook) {
rootPath = notebooks[i].getPath();
break;
}
}
Q_ASSERT(!rootPath.isEmpty());
}
fileList->handleNotebookRenamed(notebooks, oldName, newName);
}
void VFileListPanel::handleDirectoryRenamed(const QString &notebook,
const QString &oldRelativePath, const QString &newRelativePath)
{
if (notebook == this->notebook
&& oldRelativePath == relativePath) {
relativePath = newRelativePath;
}
fileList->handleDirectoryRenamed(notebook, oldRelativePath,
newRelativePath);
}
bool VFileListPanel::importFile(const QString &name)
{
return fileList->importFile(name);
}
void VFileListPanel::onNewFileBtnClicked()
{
if (relativePath.isEmpty()) {
return;
}
fileList->newFile();
}
void VFileListPanel::onDeleteFileBtnClicked()
{
QListWidgetItem *curItem = fileList->currentItem();
if (!curItem) {
return;
}
fileList->deleteFile();
}
void VFileListPanel::onFileInfoBtnClicked()
{
QListWidgetItem *curItem = fileList->currentItem();
if (!curItem) {
return;
}
QJsonObject curItemJson = curItem->data(Qt::UserRole).toJsonObject();
Q_ASSERT(!curItemJson.isEmpty());
QString curItemName = curItemJson["name"].toString();
QString info;
QString defaultName = curItemName;
do {
VFileInfoDialog dialog(tr("Note Information"), info, defaultName, this);
if (dialog.exec() == QDialog::Accepted) {
QString name = dialog.getNameInput();
if (name == curItemName) {
return;
}
if (isConflictNameWithExisting(name)) {
info = "Name already exists.\nPlease choose another name:";
defaultName = name;
continue;
}
renameFile(curItem, name);
}
break;
} while (true);
}
bool VFileListPanel::isConflictNameWithExisting(const QString &name)
{
int nrChild = fileList->count();
for (int i = 0; i < nrChild; ++i) {
QListWidgetItem *item = fileList->item(i);
QJsonObject itemJson = item->data(Qt::UserRole).toJsonObject();
Q_ASSERT(!itemJson.isEmpty());
if (itemJson["name"].toString() == name) {
return true;
}
}
return false;
}
void VFileListPanel::renameFile(QListWidgetItem *item, const QString &newName)
{
if (!item) {
return;
}
QJsonObject itemJson = item->data(Qt::UserRole).toJsonObject();
Q_ASSERT(!itemJson.isEmpty());
QString name = itemJson["name"].toString();
QString path = QDir(rootPath).filePath(relativePath);
QFile file(QDir(path).filePath(name));
QString newFilePath(QDir(path).filePath(newName));
Q_ASSERT(file.exists());
if (!file.rename(newFilePath)) {
qWarning() << "error: fail to rename file" << name << "under" << path;
QMessageBox msgBox(QMessageBox::Warning, tr("Warning"), QString("Could not rename note \"%1\" under \"%2\".")
.arg(name).arg(path), QMessageBox::Ok, this);
msgBox.setInformativeText(QString("Please check if there already exists a file named \"%1\".").arg(newName));
msgBox.exec();
return;
}
// Update directory's config file
QJsonObject dirJson = VConfigManager::readDirectoryConfig(path);
Q_ASSERT(!dirJson.isEmpty());
QJsonArray fileArray = dirJson["files"].toArray();
int index = 0;
for (index = 0; index < fileArray.size(); ++index) {
QJsonObject tmp = fileArray[index].toObject();
if (tmp["name"].toString() == name) {
tmp["name"] = newName;
fileArray[index] = tmp;
break;
}
}
Q_ASSERT(index != fileArray.size());
dirJson["files"] = fileArray;
if (!VConfigManager::writeDirectoryConfig(path, dirJson)) {
qWarning() << "error: fail to rename file"
<< name << "to" << newName;
file.rename(name);
return;
}
// Update item
itemJson["name"] = newName;
item->setData(Qt::UserRole, itemJson);
item->setText(newName);
QString oldPath = QDir::cleanPath(QDir(relativePath).filePath(name));
QString newPath = QDir::cleanPath(QDir(relativePath).filePath(newName));
qDebug() << "file renamed" << oldPath << "to" << newPath;
emit fileRenamed(notebook, oldPath, newPath);
}

70
src/vfilelistpanel.h Normal file
View File

@ -0,0 +1,70 @@
#ifndef VFILELISTPANEL_H
#define VFILELISTPANEL_H
#include <QWidget>
#include <QString>
#include <QVector>
#include <QJsonObject>
#include <QDir>
#include <QFile>
#include "vnotebook.h"
class VNote;
class VFileList;
class QPushButton;
class QListWidgetItem;
class VFileListPanel : public QWidget
{
Q_OBJECT
public:
VFileListPanel(VNote *vnote, QWidget *parent = 0);
bool importFile(const QString &name);
signals:
void fileClicked(QJsonObject fileJson);
void fileDeleted(QJsonObject fileJson);
void fileCreated(QJsonObject fileJson);
void fileRenamed(const QString &notebook, const QString &oldPath,
const QString &newPath);
public slots:
void setDirectory(QJsonObject dirJson);
void handleNotebookRenamed(const QVector<VNotebook> &notebooks, const QString &oldName,
const QString &newName);
void handleDirectoryRenamed(const QString &notebook, const QString &oldRelativePath,
const QString &newRelativePath);
private slots:
void onNewFileBtnClicked();
void onDeleteFileBtnClicked();
void onFileInfoBtnClicked();
private:
void setupUI();
bool isConflictNameWithExisting(const QString &name);
void renameFile(QListWidgetItem *item, const QString &newName);
void clearDirectoryInfo();
inline QString getDirectoryName();
VNote *vnote;
QString notebook;
// Current directory's relative path
QString relativePath;
// Used for cache
QString rootPath;
VFileList *fileList;
QPushButton *newFileBtn;
QPushButton *deleteFileBtn;
QPushButton *fileInfoBtn;
};
inline QString VFileListPanel::getDirectoryName()
{
if (relativePath.isEmpty()) {
return "";
}
return QFileInfo(QDir::cleanPath(relativePath)).fileName();
}
#endif // VFILELISTPANEL_H

View File

@ -2,7 +2,7 @@
#include "vmainwindow.h"
#include "vdirectorytree.h"
#include "vnote.h"
#include "vfilelist.h"
#include "vfilelistpanel.h"
#include "vtabwidget.h"
#include "vconfigmanager.h"
#include "dialog/vnewnotebookdialog.h"
@ -73,9 +73,8 @@ void VMainWindow::setupUI()
nbContainer->setLayout(nbLayout);
nbContainer->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Expanding);
// File list widget
fileList = new VFileList(vnote);
fileList->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Expanding);
fileListPanel = new VFileListPanel(vnote);
fileListPanel->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Expanding);
// Editor tab widget
tabs = new VTabWidget(vnote);
@ -85,7 +84,7 @@ void VMainWindow::setupUI()
// Main Splitter
mainSplitter = new QSplitter();
mainSplitter->addWidget(nbContainer);
mainSplitter->addWidget(fileList);
mainSplitter->addWidget(fileListPanel);
mainSplitter->addWidget(tabs);
mainSplitter->setStretchFactor(0, 1);
mainSplitter->setStretchFactor(1, 1);
@ -96,17 +95,17 @@ void VMainWindow::setupUI()
SLOT(setCurNotebookIndex(int)));
connect(vnote, &VNote::notebooksRenamed,
fileList, &VFileList::handleNotebookRenamed);
fileListPanel, &VFileListPanel::handleNotebookRenamed);
connect(directoryTree, &VDirectoryTree::currentDirectoryChanged,
fileList, &VFileList::setDirectory);
fileListPanel, &VFileListPanel::setDirectory);
connect(directoryTree, &VDirectoryTree::directoryRenamed,
fileList, &VFileList::handleDirectoryRenamed);
fileListPanel, &VFileListPanel::handleDirectoryRenamed);
connect(fileList, &VFileList::fileClicked,
connect(fileListPanel, &VFileListPanel::fileClicked,
tabs, &VTabWidget::openFile);
connect(fileList, &VFileList::fileDeleted,
connect(fileListPanel, &VFileListPanel::fileDeleted,
tabs, &VTabWidget::closeFile);
connect(fileList, &VFileList::fileCreated,
connect(fileListPanel, &VFileListPanel::fileCreated,
tabs, &VTabWidget::openFile);
connect(newNotebookBtn, &QPushButton::clicked,
@ -383,14 +382,18 @@ void VMainWindow::onNotebookInfoBtnClicked()
void VMainWindow::importNoteFromFile()
{
static QString lastPath = QDir::homePath();
QStringList files = QFileDialog::getOpenFileNames(this,tr("Select files(HTML or Markdown) to be imported as notes"),
QDir::homePath());
lastPath);
if (files.isEmpty()) {
return;
}
// Update lastPath
lastPath = QFileInfo(files[0]).path();
QStringList failedFiles;
for (int i = 0; i < files.size(); ++i) {
bool ret = fileList->importFile(files[i]);
bool ret = fileListPanel->importFile(files[i]);
if (!ret) {
failedFiles.append(files[i]);
}

View File

@ -11,12 +11,12 @@ class QListWidget;
class QTabWidget;
class QToolBar;
class VNote;
class VFileList;
class VTabWidget;
class QAction;
class QPushButton;
class VNotebook;
class QActionGroup;
class VFileListPanel;
class VMainWindow : public QMainWindow
{
@ -63,8 +63,8 @@ private:
QPushButton *newRootDirBtn;
QPushButton *deleteDirBtn;
QPushButton *dirInfoBtn;
VFileListPanel *fileListPanel;
VDirectoryTree *directoryTree;
VFileList *fileList;
VTabWidget *tabs;
QSplitter *mainSplitter;
VNote *vnote;

View File

@ -42,5 +42,8 @@
<file>resources/icons/create_rootdir.png</file>
<file>resources/icons/delete_dir.png</file>
<file>resources/icons/dir_info.png</file>
<file>resources/icons/create_note.png</file>
<file>resources/icons/delete_note.png</file>
<file>resources/icons/note_info.png</file>
</qresource>
</RCC>

View File

@ -54,7 +54,7 @@ void VTabWidget::openFile(QJsonObject fileJson)
mode = fileJson["mode"].toInt();
}
qDebug() << "open notebook[" << notebook << "] path[" << relativePath << "]" << mode;
qDebug() << "open notebook" << notebook << "path" << relativePath << mode;
// Find if it has been opened already
int idx = findTabByFile(notebook, relativePath);