do not inherit QListWidget in VFileList

Signed-off-by: Le Tan <tamlokveer@gmail.com>
This commit is contained in:
Le Tan 2016-10-30 17:44:21 +08:00
parent 35f8d7350c
commit 49020d9fb2
7 changed files with 185 additions and 338 deletions

View File

@ -36,7 +36,6 @@ SOURCES += main.cpp\
vmarkdownconverter.cpp \
dialog/vnotebookinfodialog.cpp \
dialog/vdirinfodialog.cpp \
vfilelistpanel.cpp \
dialog/vfileinfodialog.cpp
HEADERS += vmainwindow.h \
@ -64,7 +63,6 @@ HEADERS += vmainwindow.h \
vmarkdownconverter.h \
dialog/vnotebookinfodialog.h \
dialog/vdirinfodialog.h \
vfilelistpanel.h \
dialog/vfileinfodialog.h
RESOURCES += \

View File

@ -3,18 +3,52 @@
#include "vfilelist.h"
#include "vconfigmanager.h"
#include "dialog/vnewfiledialog.h"
#include "dialog/vfileinfodialog.h"
#include "vnote.h"
VFileList::VFileList(VNote *vnote, QWidget *parent)
: QListWidget(parent), vnote(vnote)
: QWidget(parent), vnote(vnote)
{
setContextMenuPolicy(Qt::CustomContextMenu);
setupUI();
initActions();
}
connect(this, &VFileList::customContextMenuRequested,
void VFileList::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 QListWidget(this);
fileList->setContextMenuPolicy(Qt::CustomContextMenu);
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(newFileBtn, &QPushButton::clicked,
this, &VFileList::onNewFileBtnClicked);
connect(deleteFileBtn, &QPushButton::clicked,
this, &VFileList::onDeleteFileBtnClicked);
connect(fileInfoBtn, &QPushButton::clicked,
this, &VFileList::onFileInfoBtnClicked);
connect(fileList, &QListWidget::customContextMenuRequested,
this, &VFileList::contextMenuRequested);
connect(this, &VFileList::itemClicked,
connect(fileList, &QListWidget::itemClicked,
this, &VFileList::handleItemClicked);
setLayout(mainLayout);
}
void VFileList::initActions()
@ -32,6 +66,7 @@ void VFileList::initActions()
void VFileList::setDirectory(QJsonObject dirJson)
{
fileList->clear();
if (dirJson.isEmpty()) {
clearDirectoryInfo();
return;
@ -59,7 +94,6 @@ void VFileList::clearDirectoryInfo()
void VFileList::updateFileList()
{
clear();
QString path = QDir(rootPath).filePath(relativePath);
if (!QDir(path).exists()) {
@ -91,6 +125,54 @@ void VFileList::updateFileList()
}
}
void VFileList::onNewFileBtnClicked()
{
if (relativePath.isEmpty()) {
return;
}
newFile();
}
void VFileList::onDeleteFileBtnClicked()
{
QListWidgetItem *curItem = fileList->currentItem();
if (!curItem) {
return;
}
deleteFile();
}
void VFileList::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);
}
QListWidgetItem* VFileList::insertFileListItem(QJsonObject fileJson, bool atFront)
{
Q_ASSERT(!fileJson.isEmpty());
@ -98,23 +180,23 @@ QListWidgetItem* VFileList::insertFileListItem(QJsonObject fileJson, bool atFron
item->setData(Qt::UserRole, fileJson);
if (atFront) {
insertItem(0, item);
fileList->insertItem(0, item);
} else {
addItem(item);
fileList->addItem(item);
}
// Qt seems not to update the QListWidget correctly. Manually force it to repaint.
update();
fileList->update();
qDebug() << "add new list item:" << fileJson["name"].toString();
return item;
}
void VFileList::removeFileListItem(QListWidgetItem *item)
{
setCurrentRow(-1);
removeItemWidget(item);
fileList->setCurrentRow(-1);
fileList->removeItemWidget(item);
delete item;
// Qt seems not to update the QListWidget correctly. Manually force it to repaint.
update();
fileList->update();
}
void VFileList::newFile()
@ -133,9 +215,9 @@ void VFileList::newFile()
}
QListWidgetItem *newItem = createFileAndUpdateList(name);
if (newItem) {
setCurrentItem(newItem);
fileList->setCurrentItem(newItem);
// Qt seems not to update the QListWidget correctly. Manually force it to repaint.
update();
fileList->update();
// Open this file in edit mode
QJsonObject itemJson = newItem->data(Qt::UserRole).toJsonObject();
@ -152,7 +234,7 @@ void VFileList::newFile()
void VFileList::deleteFile()
{
QListWidgetItem *curItem = currentItem();
QListWidgetItem *curItem = fileList->currentItem();
Q_ASSERT(curItem);
QJsonObject curItemJson = curItem->data(Qt::UserRole).toJsonObject();
QString curItemName = curItemJson["name"].toString();
@ -175,7 +257,7 @@ void VFileList::deleteFile()
void VFileList::contextMenuRequested(QPoint pos)
{
QListWidgetItem *item = itemAt(pos);
QListWidgetItem *item = fileList->itemAt(pos);
QMenu menu(this);
if (notebook.isEmpty()) {
@ -186,14 +268,14 @@ void VFileList::contextMenuRequested(QPoint pos)
menu.addAction(deleteFileAct);
}
menu.exec(mapToGlobal(pos));
menu.exec(fileList->mapToGlobal(pos));
}
bool VFileList::isConflictNameWithExisting(const QString &name)
{
int nrChild = this->count();
int nrChild = fileList->count();
for (int i = 0; i < nrChild; ++i) {
QListWidgetItem *item = this->item(i);
QListWidgetItem *item = fileList->item(i);
QJsonObject itemJson = item->data(Qt::UserRole).toJsonObject();
Q_ASSERT(!itemJson.isEmpty());
if (itemJson["name"].toString() == name) {
@ -288,7 +370,7 @@ void VFileList::handleItemClicked(QListWidgetItem *currentItem)
return;
}
// Qt seems not to update the QListWidget correctly. Manually force it to repaint.
update();
fileList->update();
QJsonObject itemJson = currentItem->data(Qt::UserRole).toJsonObject();
Q_ASSERT(!itemJson.isEmpty());
itemJson["notebook"] = notebook;
@ -365,3 +447,57 @@ void VFileList::handleDirectoryRenamed(const QString &notebook,
relativePath = newRelativePath;
}
}
void VFileList::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);
}

View File

@ -1,7 +1,7 @@
#ifndef VFILELIST_H
#define VFILELIST_H
#include <QListWidget>
#include <QWidget>
#include <QJsonObject>
#include <QFileInfo>
#include <QDir>
@ -9,8 +9,11 @@
class QAction;
class VNote;
class QListWidget;
class QListWidgetItem;
class QPushButton;
class VFileList : public QListWidget
class VFileList : public QWidget
{
Q_OBJECT
public:
@ -21,10 +24,15 @@ signals:
void fileClicked(QJsonObject fileJson);
void fileDeleted(QJsonObject fileJson);
void fileCreated(QJsonObject fileJson);
void fileRenamed(const QString &notebook, const QString &oldPath,
const QString &newPath);
private slots:
void contextMenuRequested(QPoint pos);
void handleItemClicked(QListWidgetItem *currentItem);
void onNewFileBtnClicked();
void onDeleteFileBtnClicked();
void onFileInfoBtnClicked();
public slots:
void setDirectory(QJsonObject dirJson);
@ -36,6 +44,7 @@ public slots:
void deleteFile();
private:
void setupUI();
void updateFileList();
QListWidgetItem *insertFileListItem(QJsonObject fileJson, bool atFront = false);
void removeFileListItem(QListWidgetItem *item);
@ -45,6 +54,7 @@ private:
void deleteFileAndUpdateList(QListWidgetItem *item);
void clearDirectoryInfo();
inline QString getDirectoryName();
void renameFile(QListWidgetItem *item, const QString &newName);
VNote *vnote;
QString notebook;
@ -53,6 +63,11 @@ private:
// Used for cache
QString rootPath;
QListWidget *fileList;
QPushButton *newFileBtn;
QPushButton *deleteFileBtn;
QPushButton *fileInfoBtn;
// Actions
QAction *newFileAct;
QAction *deleteFileAct;

View File

@ -1,232 +0,0 @@
#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);
}

View File

@ -1,70 +0,0 @@
#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 "vfilelistpanel.h"
#include "vfilelist.h"
#include "vtabwidget.h"
#include "vconfigmanager.h"
#include "dialog/vnewnotebookdialog.h"
@ -75,8 +75,8 @@ void VMainWindow::setupUI()
nbContainer->setLayout(nbLayout);
nbContainer->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Expanding);
fileListPanel = new VFileListPanel(vnote);
fileListPanel->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Expanding);
fileList = new VFileList(vnote);
fileList->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Expanding);
// Editor tab widget
tabs = new VTabWidget(vnote);
@ -86,7 +86,7 @@ void VMainWindow::setupUI()
// Main Splitter
mainSplitter = new QSplitter();
mainSplitter->addWidget(nbContainer);
mainSplitter->addWidget(fileListPanel);
mainSplitter->addWidget(fileList);
mainSplitter->addWidget(tabs);
mainSplitter->setStretchFactor(0, 1);
mainSplitter->setStretchFactor(1, 1);
@ -97,17 +97,17 @@ void VMainWindow::setupUI()
SLOT(setCurNotebookIndex(int)));
connect(vnote, &VNote::notebooksRenamed,
fileListPanel, &VFileListPanel::handleNotebookRenamed);
fileList, &VFileList::handleNotebookRenamed);
connect(directoryTree, &VDirectoryTree::currentDirectoryChanged,
fileListPanel, &VFileListPanel::setDirectory);
fileList, &VFileList::setDirectory);
connect(directoryTree, &VDirectoryTree::directoryRenamed,
fileListPanel, &VFileListPanel::handleDirectoryRenamed);
fileList, &VFileList::handleDirectoryRenamed);
connect(fileListPanel, &VFileListPanel::fileClicked,
connect(fileList, &VFileList::fileClicked,
tabs, &VTabWidget::openFile);
connect(fileListPanel, &VFileListPanel::fileDeleted,
connect(fileList, &VFileList::fileDeleted,
tabs, &VTabWidget::closeFile);
connect(fileListPanel, &VFileListPanel::fileCreated,
connect(fileList, &VFileList::fileCreated,
tabs, &VTabWidget::openFile);
connect(newNotebookBtn, &QPushButton::clicked,
@ -454,7 +454,7 @@ void VMainWindow::importNoteFromFile()
QStringList failedFiles;
for (int i = 0; i < files.size(); ++i) {
bool ret = fileListPanel->importFile(files[i]);
bool ret = fileList->importFile(files[i]);
if (!ret) {
failedFiles.append(files[i]);
}

View File

@ -16,7 +16,7 @@ class QAction;
class QPushButton;
class VNotebook;
class QActionGroup;
class VFileListPanel;
class VFileList;
class VMainWindow : public QMainWindow
{
@ -70,7 +70,7 @@ private:
QPushButton *newRootDirBtn;
QPushButton *deleteDirBtn;
QPushButton *dirInfoBtn;
VFileListPanel *fileListPanel;
VFileList *fileList;
VDirectoryTree *directoryTree;
VTabWidget *tabs;
QSplitter *mainSplitter;