diff --git a/src/resources/icons/copy.svg b/src/resources/icons/copy.svg new file mode 100644 index 00000000..75b8c0ba --- /dev/null +++ b/src/resources/icons/copy.svg @@ -0,0 +1,11 @@ + + + + + + + + + diff --git a/src/resources/icons/cut.svg b/src/resources/icons/cut.svg new file mode 100644 index 00000000..264e7c2b --- /dev/null +++ b/src/resources/icons/cut.svg @@ -0,0 +1,23 @@ + + + + + + + + + + diff --git a/src/resources/icons/paste.svg b/src/resources/icons/paste.svg new file mode 100644 index 00000000..84bb8e29 --- /dev/null +++ b/src/resources/icons/paste.svg @@ -0,0 +1,14 @@ + + + + + + + + + diff --git a/src/src.pro b/src/src.pro index b2f3c755..a03493c6 100644 --- a/src/src.pro +++ b/src/src.pro @@ -42,7 +42,8 @@ SOURCES += main.cpp\ veditwindow.cpp \ vedittab.cpp \ voutline.cpp \ - vtoc.cpp + vtoc.cpp \ + vfilelocation.cpp HEADERS += vmainwindow.h \ vdirectorytree.h \ @@ -73,7 +74,8 @@ HEADERS += vmainwindow.h \ veditwindow.h \ vedittab.h \ voutline.h \ - vtoc.h + vtoc.h \ + vfilelocation.h RESOURCES += \ vnote.qrc diff --git a/src/utils/vutils.cpp b/src/utils/vutils.cpp index 2b4b8307..3c1051e3 100644 --- a/src/utils/vutils.cpp +++ b/src/utils/vutils.cpp @@ -4,6 +4,11 @@ #include #include #include +#include +#include +#include +#include +#include VUtils::VUtils() { @@ -159,3 +164,42 @@ void VUtils::makeDirectory(const QString &path) qDebug() << "mkdir" << path; } } + +ClipboardOpType VUtils::opTypeInClipboard() +{ + QClipboard *clipboard = QApplication::clipboard(); + const QMimeData *mimeData = clipboard->mimeData(); + + if (mimeData->hasText()) { + QString text = mimeData->text(); + QJsonObject clip = QJsonDocument::fromJson(text.toLocal8Bit()).object(); + if (clip.contains("operation")) { + return (ClipboardOpType)clip["operation"].toInt(); + } + } + return ClipboardOpType::Invalid; +} + +bool VUtils::copyFile(const QString &p_srcFilePath, const QString &p_destFilePath, bool p_isCut) +{ + QString srcPath = QDir::cleanPath(p_srcFilePath); + QString destPath = QDir::cleanPath(p_destFilePath); + + if (srcPath == destPath) { + return true; + } + + if (p_isCut) { + QFile file(srcPath); + if (!file.rename(destPath)) { + qWarning() << "error: fail to copy file" << srcPath << destPath; + return false; + } + } else { + if (!QFile::copy(srcPath, destPath)) { + qWarning() << "error: fail to copy file" << srcPath << destPath; + return false; + } + } + return true; +} diff --git a/src/utils/vutils.h b/src/utils/vutils.h index 0fe70145..7e5ad932 100644 --- a/src/utils/vutils.h +++ b/src/utils/vutils.h @@ -6,6 +6,7 @@ #include #include #include "vconfigmanager.h" +#include "vconstants.h" class VUtils { @@ -25,6 +26,8 @@ public: static QString basePathFromPath(const QString &path); static QVector imagesFromMarkdownFile(const QString &filePath); static void makeDirectory(const QString &path); + static ClipboardOpType opTypeInClipboard(); + static bool copyFile(const QString &p_srcFilePath, const QString &p_destFilePath, bool p_isCut); private: static inline void addQssVarToMap(QVector > &map, const QString &key, const QString &value); diff --git a/src/vconstants.h b/src/vconstants.h index cdd19d40..eadcd9e2 100644 --- a/src/vconstants.h +++ b/src/vconstants.h @@ -2,5 +2,6 @@ #define VCONSTANTS_H enum class DocType { Html, Markdown }; +enum class ClipboardOpType { Invalid, CopyFile, CopyDir }; #endif diff --git a/src/veditarea.cpp b/src/veditarea.cpp index 9290963c..efa3b2df 100644 --- a/src/veditarea.cpp +++ b/src/veditarea.cpp @@ -242,13 +242,14 @@ void VEditArea::handleDirectoryRenamed(const QString ¬ebook, const QString &o updateWindowStatus(); } -void VEditArea::handleFileRenamed(const QString ¬ebook, - const QString &oldRelativePath, const QString &newRelativePath) +void VEditArea::handleFileRenamed(const QString &p_srcNotebook, const QString &p_srcRelativePath, + const QString &p_destNotebook, const QString &p_destRelativePath) { + qDebug() << "fileRenamed" << p_srcNotebook << p_srcRelativePath << p_destNotebook << p_destRelativePath; int nrWin = splitter->count(); for (int i = 0; i < nrWin; ++i) { VEditWindow *win = getWindow(i); - win->handleFileRenamed(notebook, oldRelativePath, newRelativePath); + win->handleFileRenamed(p_srcNotebook, p_srcRelativePath, p_destNotebook, p_destRelativePath); } updateWindowStatus(); } diff --git a/src/veditarea.h b/src/veditarea.h index 26a8b1ba..73db00a5 100644 --- a/src/veditarea.h +++ b/src/veditarea.h @@ -44,8 +44,8 @@ public slots: void handleOutlineItemActivated(const VAnchor &anchor); void handleDirectoryRenamed(const QString ¬ebook, const QString &oldRelativePath, const QString &newRelativePath); - void handleFileRenamed(const QString ¬ebook, - const QString &oldRelativePath, const QString &newRelativePath); + void handleFileRenamed(const QString &p_srcNotebook, const QString &p_srcRelativePath, + const QString &p_destNotebook, const QString &p_destRelativePath); private slots: void handleSplitWindowRequest(VEditWindow *curWindow); diff --git a/src/veditwindow.cpp b/src/veditwindow.cpp index 1c4143a8..a4b9c82c 100644 --- a/src/veditwindow.cpp +++ b/src/veditwindow.cpp @@ -280,23 +280,23 @@ void VEditWindow::handleDirectoryRenamed(const QString ¬ebook, const QString updateTabListMenu(); } -void VEditWindow::handleFileRenamed(const QString ¬ebook, const QString &oldRelativePath, - const QString &newRelativePath) +void VEditWindow::handleFileRenamed(const QString &p_srcNotebook, const QString &p_srcRelativePath, + const QString &p_destNotebook, const QString &p_destRelativePath) { QTabBar *tabs = tabBar(); int nrTabs = tabs->count(); for (int i = 0; i < nrTabs; ++i) { QJsonObject tabJson = tabs->tabData(i).toJsonObject(); - if (tabJson["notebook"].toString() == notebook) { + if (tabJson["notebook"].toString() == p_srcNotebook) { QString relativePath = tabJson["relative_path"].toString(); - if (relativePath == oldRelativePath) { + if (relativePath == p_srcRelativePath) { VEditTab *tab = getTab(i); - relativePath = newRelativePath; - tabJson["relative_path"] = relativePath; + tabJson["notebook"] = p_destNotebook; + tabJson["relative_path"] = p_destRelativePath; tabs->setTabData(i, tabJson); tabs->setTabToolTip(i, generateTooltip(tabJson)); - tabs->setTabText(i, generateTabText(VUtils::fileNameFromPath(relativePath), tab->isModified())); - QString path = QDir::cleanPath(QDir(vnote->getNotebookPath(notebook)).filePath(relativePath)); + tabs->setTabText(i, generateTabText(VUtils::fileNameFromPath(p_destRelativePath), tab->isModified())); + QString path = QDir::cleanPath(QDir(vnote->getNotebookPath(p_destNotebook)).filePath(p_destRelativePath)); tab->updatePath(path); } } diff --git a/src/veditwindow.h b/src/veditwindow.h index 9ea74f56..63042556 100644 --- a/src/veditwindow.h +++ b/src/veditwindow.h @@ -39,8 +39,8 @@ public: void scrollCurTab(const VAnchor &anchor); void handleDirectoryRenamed(const QString ¬ebook, const QString &oldRelativePath, const QString &newRelativePath); - void handleFileRenamed(const QString ¬ebook, - const QString &oldRelativePath, const QString &newRelativePath); + void handleFileRenamed(const QString &p_srcNotebook, const QString &p_srcRelativePath, + const QString &p_destNotebook, const QString &p_destRelativePath); protected: void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE; diff --git a/src/vfilelist.cpp b/src/vfilelist.cpp index da152638..e548ed74 100644 --- a/src/vfilelist.cpp +++ b/src/vfilelist.cpp @@ -51,6 +51,24 @@ void VFileList::initActions() fileInfoAct->setStatusTip(tr("View and edit current note's information")); connect(fileInfoAct, &QAction::triggered, this, &VFileList::curFileInfo); + + copyAct = new QAction(QIcon(":/resources/icons/copy.svg"), + tr("&Copy"), this); + copyAct->setStatusTip(tr("Copy selected notes")); + connect(copyAct, &QAction::triggered, + this, &VFileList::copySelectedFiles); + + cutAct = new QAction(QIcon(":/resources/icons/cut.svg"), + tr("&Cut"), this); + cutAct->setStatusTip(tr("Cut selected notes")); + connect(cutAct, &QAction::triggered, + this, &VFileList::cutSelectedFiles); + + pasteAct = new QAction(QIcon(":/resources/icons/paste.svg"), + tr("&Paste"), this); + pasteAct->setStatusTip(tr("Paste notes")); + connect(pasteAct, &QAction::triggered, + this, &VFileList::pasteFilesInCurDir); } void VFileList::setDirectory(QJsonObject dirJson) @@ -88,6 +106,7 @@ void VFileList::updateFileList() { QString path = QDir(rootPath).filePath(relativePath); + fileList->clear(); if (!QDir(path).exists()) { qDebug() << "invalid notebook directory:" << path; QMessageBox msgBox(QMessageBox::Warning, tr("Warning"), tr("Invalid notebook directory."), @@ -144,7 +163,8 @@ void VFileList::fileInfo(const QString &p_notebook, const QString &p_relativePat defaultName = name; continue; } - renameFile(p_notebook, p_relativePath, name); + copyFile(p_notebook, p_relativePath, p_notebook, + QDir(VUtils::basePathFromPath(p_relativePath)).filePath(name), true); } break; } while (true); @@ -252,8 +272,13 @@ void VFileList::contextMenuRequested(QPoint pos) if (item) { menu.addAction(deleteFileAct); menu.addAction(fileInfoAct); + menu.addAction(copyAct); + menu.addAction(cutAct); } + if (VUtils::opTypeInClipboard() == ClipboardOpType::CopyFile) { + menu.addAction(pasteAct); + } menu.exec(fileList->mapToGlobal(pos)); } @@ -306,52 +331,20 @@ QListWidgetItem* VFileList::createFileAndUpdateList(const QString &name) file.close(); qDebug() << "create file:" << filePath; - // Update current directory's config file to include this new file - QJsonObject dirJson = VConfigManager::readDirectoryConfig(path); - Q_ASSERT(!dirJson.isEmpty()); - QJsonObject fileJson; - fileJson["name"] = name; - QJsonArray fileArray = dirJson["files"].toArray(); - fileArray.push_front(fileJson); - dirJson["files"] = fileArray; - if (!VConfigManager::writeDirectoryConfig(path, dirJson)) { - qWarning() << "error: fail to update directory's configuration file to add a new file" - << name; + if (!addFileInConfig(filePath, 0)) { file.remove(); return NULL; } - return insertFileListItem(fileJson, true); + return insertFileListItem(readFileInConfig(filePath), true); } void VFileList::deleteFileAndUpdateList(const QString &p_notebook, const QString &p_relativePath) { - QString path = QDir(vnote->getNotebookPath(p_notebook)).filePath(VUtils::basePathFromPath(p_relativePath)); - QString fileName = VUtils::fileNameFromPath(p_relativePath); - QString filePath = QDir(path).filePath(fileName); + QString filePath = QDir(vnote->getNotebookPath(p_notebook)).filePath(p_relativePath); - // Update current directory's config file to exclude this file - QJsonObject dirJson = VConfigManager::readDirectoryConfig(path); - Q_ASSERT(!dirJson.isEmpty()); - QJsonArray fileArray = dirJson["files"].toArray(); - bool deleted = false; - for (int i = 0; i < fileArray.size(); ++i) { - QJsonObject ele = fileArray[i].toObject(); - if (ele["name"].toString() == fileName) { - fileArray.removeAt(i); - deleted = true; - break; - } - } - if (!deleted) { - qWarning() << "error: fail to find" << fileName << "to delete"; - return; - } - dirJson["files"] = fileArray; - if (!VConfigManager::writeDirectoryConfig(path, dirJson)) { - qWarning() << "error: fail to update directory's configuration file to delete" - << fileName; + if (!removeFileInConfig(filePath)) { return; } @@ -446,86 +439,6 @@ void VFileList::handleDirectoryRenamed(const QString ¬ebook, } } -// @p_relativePath contains the flie name -void VFileList::renameFile(const QString &p_notebook, - const QString &p_relativePath, const QString &p_newName) -{ - QString name = VUtils::fileNameFromPath(p_relativePath); - - // If change the file type, we need to convert it - DocType docType = VUtils::isMarkdown(name) ? DocType::Markdown : DocType::Html; - DocType newDocType = VUtils::isMarkdown(p_newName) ? DocType::Markdown : DocType::Html; - if (docType != newDocType) { - if (editArea->isFileOpened(p_notebook, p_relativePath)) { - QMessageBox msgBox(QMessageBox::Warning, tr("Warning"), QString("Rename will change the note type"), - QMessageBox::Ok | QMessageBox::Cancel, this); - msgBox.setDefaultButton(QMessageBox::Ok); - msgBox.setInformativeText(QString("You should close the note %1 before continue").arg(name)); - if (QMessageBox::Ok == msgBox.exec()) { - QJsonObject curItemJson; - curItemJson["notebook"] = p_notebook; - curItemJson["relative_path"] = p_relativePath; - curItemJson["is_forced"] = false; - if (!editArea->closeFile(curItemJson)) { - return; - } - } else { - return; - } - } - convertFileType(p_notebook, p_relativePath, docType, newDocType); - } - - QString path = QDir(vnote->getNotebookPath(p_notebook)).filePath(VUtils::basePathFromPath(p_relativePath)); - QFile file(QDir(path).filePath(name)); - QString newFilePath(QDir(path).filePath(p_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(p_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"] = p_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" << p_newName; - file.rename(name); - return; - } - - // Update item - QListWidgetItem *item = findItem(p_notebook, p_relativePath); - if (item) { - QJsonObject itemJson = item->data(Qt::UserRole).toJsonObject(); - itemJson["name"] = p_newName; - item->setData(Qt::UserRole, itemJson); - item->setText(p_newName); - } - - QString oldPath = QDir::cleanPath(p_relativePath); - QString newPath = QDir::cleanPath(QDir(VUtils::basePathFromPath(p_relativePath)).filePath(p_newName)); - qDebug() << "file renamed" << oldPath << "to" << newPath; - emit fileRenamed(p_notebook, oldPath, newPath); -} - void VFileList::convertFileType(const QString ¬ebook, const QString &fileRelativePath, DocType oldType, DocType newType) { @@ -559,3 +472,258 @@ void VFileList::deleteLocalImages(const QString &filePath) } qDebug() << "delete" << deleted << "images for" << filePath; } + +void VFileList::copySelectedFiles(bool p_isCut) +{ + QList items = fileList->selectedItems(); + if (items.isEmpty()) { + return; + } + QJsonArray files; + QDir dir(relativePath); + for (int i = 0; i < items.size(); ++i) { + QJsonObject itemJson = items[i]->data(Qt::UserRole).toJsonObject(); + QString itemName = itemJson["name"].toString(); + QJsonObject fileJson; + fileJson["notebook"] = notebook; + fileJson["relative_path"] = dir.filePath(itemName); + files.append(fileJson); + } + + copyFileInfoToClipboard(files, p_isCut); +} + +void VFileList::cutSelectedFiles() +{ + copySelectedFiles(true); +} + +void VFileList::copyFileInfoToClipboard(const QJsonArray &p_files, bool p_isCut) +{ + QJsonObject clip; + clip["operation"] = (int)ClipboardOpType::CopyFile; + clip["is_cut"] = p_isCut; + clip["sources"] = p_files; + + QClipboard *clipboard = QApplication::clipboard(); + clipboard->setText(QJsonDocument(clip).toJson(QJsonDocument::Compact)); +} + +void VFileList::pasteFilesInCurDir() +{ + pasteFiles(notebook, relativePath); +} + +void VFileList::pasteFiles(const QString &p_notebook, const QString &p_dirRelativePath) +{ + qDebug() << "paste files to" << p_notebook << p_dirRelativePath; + QClipboard *clipboard = QApplication::clipboard(); + QString text = clipboard->text(); + QJsonObject clip = QJsonDocument::fromJson(text.toLocal8Bit()).object(); + Q_ASSERT(!clip.isEmpty() && clip["operation"] == (int)ClipboardOpType::CopyFile); + + bool isCut = clip["is_cut"].toBool(); + QJsonArray sources = clip["sources"].toArray(); + + int nrFiles = sources.size(); + QDir destDir(p_dirRelativePath); + int nrPasted = 0; + for (int i = 0; i < nrFiles; ++i) { + QJsonObject file = sources[i].toObject(); + QString srcNotebook = file["notebook"].toString(); + QString srcRelativePath = file["relative_path"].toString(); + bool ret = copyFile(srcNotebook, srcRelativePath, p_notebook, + destDir.filePath(VUtils::fileNameFromPath(srcRelativePath)), isCut); + if (ret) { + nrPasted++; + } + } + qDebug() << "pasted" << nrPasted << "files sucessfully"; + clipboard->clear(); +} + +bool VFileList::copyFile(const QString &p_srcNotebook, const QString &p_srcRelativePath, + const QString &p_destNotebook, const QString &p_destRelativePath, + bool p_isCut) +{ + QString srcPath = QDir(vnote->getNotebookPath(p_srcNotebook)).filePath(p_srcRelativePath); + srcPath = QDir::cleanPath(srcPath); + QString destPath = QDir(vnote->getNotebookPath(p_destNotebook)).filePath(p_destRelativePath); + destPath = QDir::cleanPath(destPath); + if (srcPath == destPath) { + return true; + } + + // If change the file type, we need to convert it + bool needConversion = false; + DocType docType = VUtils::isMarkdown(srcPath) ? DocType::Markdown : DocType::Html; + DocType newDocType = VUtils::isMarkdown(destPath) ? DocType::Markdown : DocType::Html; + if (docType != newDocType) { + if (editArea->isFileOpened(p_srcNotebook, p_srcRelativePath)) { + QMessageBox msgBox(QMessageBox::Warning, tr("Warning"), QString("Rename will change the note type"), + QMessageBox::Ok | QMessageBox::Cancel, this); + msgBox.setDefaultButton(QMessageBox::Ok); + msgBox.setInformativeText(QString("You should close the note %1 before continue") + .arg(VUtils::fileNameFromPath(p_srcRelativePath))); + if (QMessageBox::Ok == msgBox.exec()) { + QJsonObject curItemJson; + curItemJson["notebook"] = p_srcNotebook; + curItemJson["relative_path"] = p_srcRelativePath; + curItemJson["is_forced"] = false; + if (!editArea->closeFile(curItemJson)) { + return false; + } + } else { + return false; + } + } + // Convert it later + needConversion = true; + } + + QVector images; + if (docType == DocType::Markdown) { + images = VUtils::imagesFromMarkdownFile(srcPath); + } + + // Copy the file + if (!VUtils::copyFile(srcPath, destPath, p_isCut)) { + QMessageBox msgBox(QMessageBox::Warning, tr("Warning"), QString("Fail to copy %1 from %2.") + .arg(p_srcRelativePath).arg(p_srcNotebook), QMessageBox::Ok, this); + msgBox.setInformativeText(QString("Please check if there already exists a file with the same name")); + msgBox.exec(); + return false; + } + + if (needConversion) { + convertFileType(p_destNotebook, p_destRelativePath, docType, newDocType); + } + + // We need to copy images when it is still markdown + if (!images.isEmpty()) { + if (newDocType == DocType::Markdown) { + QString dirPath = QDir(VUtils::basePathFromPath(destPath)).filePath("images"); + VUtils::makeDirectory(dirPath); + int nrPasted = 0; + for (int i = 0; i < images.size(); ++i) { + if (!QFile(images[i]).exists()) { + continue; + } + + QString destImagePath = QDir(dirPath).filePath(VUtils::fileNameFromPath(images[i])); + if (VUtils::copyFile(images[i], destImagePath, p_isCut)) { + nrPasted++; + } else { + QMessageBox msgBox(QMessageBox::Warning, tr("Warning"), QString("Fail to copy image %1.") + .arg(images[i]), QMessageBox::Ok, this); + msgBox.setInformativeText(QString("Please check if there already exists a file with the same name and manually copy it")); + msgBox.exec(); + } + } + qDebug() << "pasted" << nrPasted << "images sucessfully"; + } else { + // Delete the images + for (int i = 0; i < images.size(); ++i) { + QFile file(images[i]); + file.remove(); + } + } + } + + int idx = -1; + if (p_isCut) { + // Remove src in the config + idx = removeFileInConfig(srcPath); + if (VUtils::basePathFromPath(srcPath) != VUtils::basePathFromPath(destPath)) { + idx = -1; + } + } + + // Add dest in the config + addFileInConfig(destPath, idx); + + updateFileList(); + + if (p_isCut) { + emit fileRenamed(p_srcNotebook, p_srcRelativePath, + p_destNotebook, p_destRelativePath); + } + return true; +} + +int VFileList::removeFileInConfig(const QString &p_filePath) +{ + QString dirPath = VUtils::basePathFromPath(p_filePath); + QString fileName = VUtils::fileNameFromPath(p_filePath); + // Update current directory's config file to exclude this file + QJsonObject dirJson = VConfigManager::readDirectoryConfig(dirPath); + Q_ASSERT(!dirJson.isEmpty()); + QJsonArray fileArray = dirJson["files"].toArray(); + bool deleted = false; + int idx = -1; + for (int i = 0; i < fileArray.size(); ++i) { + QJsonObject ele = fileArray[i].toObject(); + if (ele["name"].toString() == fileName) { + fileArray.removeAt(i); + deleted = true; + idx = i; + break; + } + } + if (!deleted) { + qWarning() << "error: fail to find" << fileName << "to delete"; + return idx; + } + dirJson["files"] = fileArray; + if (!VConfigManager::writeDirectoryConfig(dirPath, dirJson)) { + qWarning() << "error: fail to update directory's configuration file to delete" + << fileName; + return idx; + } + return idx; +} + +// @index = -1, add it to the end of the list +bool VFileList::addFileInConfig(const QString &p_filePath, int p_index) +{ + QString dirPath = VUtils::basePathFromPath(p_filePath); + QString fileName = VUtils::fileNameFromPath(p_filePath); + + // Update current directory's config file to include this file + QJsonObject dirJson = VConfigManager::readDirectoryConfig(dirPath); + Q_ASSERT(!dirJson.isEmpty()); + QJsonObject fileJson; + fileJson["name"] = fileName; + QJsonArray fileArray = dirJson["files"].toArray(); + if (p_index == -1) { + p_index = fileArray.size(); + } + fileArray.insert(p_index, fileJson); + dirJson["files"] = fileArray; + if (!VConfigManager::writeDirectoryConfig(dirPath, dirJson)) { + qWarning() << "error: fail to update directory's configuration file to add a new file" + << fileName; + return false; + } + + return true; +} + +QJsonObject VFileList::readFileInConfig(const QString &p_filePath) +{ + QString dirPath = VUtils::basePathFromPath(p_filePath); + QString fileName = VUtils::fileNameFromPath(p_filePath); + + QJsonObject dirJson = VConfigManager::readDirectoryConfig(dirPath); + Q_ASSERT(!dirJson.isEmpty()); + + qDebug() << "config" << p_filePath; + QJsonArray fileArray = dirJson["files"].toArray(); + for (int i = 0; i < fileArray.size(); ++i) { + QJsonObject ele = fileArray[i].toObject(); + if (ele["name"].toString() == fileName) { + return ele; + } + } + return QJsonObject(); +} diff --git a/src/vfilelist.h b/src/vfilelist.h index 8215e61e..efb5a604 100644 --- a/src/vfilelist.h +++ b/src/vfilelist.h @@ -29,8 +29,8 @@ signals: void fileClicked(QJsonObject fileJson); void fileDeleted(QJsonObject fileJson); void fileCreated(QJsonObject fileJson); - void fileRenamed(const QString ¬ebook, const QString &oldPath, - const QString &newPath); + void fileRenamed(const QString &p_srcNotebook, const QString &p_srcRelativePath, + const QString &p_destNotebook, const QString &p_destRelativePath); void directoryChanged(const QString ¬ebook, const QString &relativePath); private slots: @@ -38,6 +38,9 @@ private slots: void handleItemClicked(QListWidgetItem *currentItem); void curFileInfo(); void deleteCurFile(); + void copySelectedFiles(bool p_isCut = false); + void cutSelectedFiles(); + void pasteFilesInCurDir(); public slots: void setDirectory(QJsonObject dirJson); @@ -58,12 +61,18 @@ private: void deleteFileAndUpdateList(const QString &p_notebook, const QString &p_relativePath); void clearDirectoryInfo(); - void renameFile(const QString &p_notebook, - const QString &p_relativePath, const QString &p_newName); void convertFileType(const QString ¬ebook, const QString &fileRelativePath, DocType oldType, DocType newType); QListWidgetItem *findItem(const QString &p_notebook, const QString &p_relativePath); void deleteLocalImages(const QString &filePath); + void copyFileInfoToClipboard(const QJsonArray &p_files, bool p_isCut); + void pasteFiles(const QString &p_notebook, const QString &p_dirRelativePath); + bool copyFile(const QString &p_srcNotebook, const QString &p_srcRelativePath, + const QString &p_destNotebook, const QString &p_destRelativePath, + bool p_isCut); + int removeFileInConfig(const QString &p_filePath); + bool addFileInConfig(const QString &p_filePath, int p_index); + QJsonObject readFileInConfig(const QString &p_filePath); VNote *vnote; QString notebook; @@ -80,6 +89,9 @@ private: QAction *newFileAct; QAction *deleteFileAct; QAction *fileInfoAct; + QAction *copyAct; + QAction *cutAct; + QAction *pasteAct; }; inline void VFileList::setEditArea(VEditArea *editArea) diff --git a/src/vfilelocation.cpp b/src/vfilelocation.cpp new file mode 100644 index 00000000..7361f269 --- /dev/null +++ b/src/vfilelocation.cpp @@ -0,0 +1,10 @@ +#include "vfilelocation.h" + +VFileLocation::VFileLocation() +{ +} + +VFileLocation::VFileLocation(const QString &p_notebook, const QString &p_relativePath) + : m_notebook(p_notebook), m_relativePath(p_relativePath) +{ +} diff --git a/src/vfilelocation.h b/src/vfilelocation.h new file mode 100644 index 00000000..b11a8bc0 --- /dev/null +++ b/src/vfilelocation.h @@ -0,0 +1,15 @@ +#ifndef VFILELOCATION_H +#define VFILELOCATION_H + +#include + +class VFileLocation +{ +public: + VFileLocation(); + VFileLocation(const QString &p_notebook, const QString &p_relativePath); + QString m_notebook; + QString m_relativePath; +}; + +#endif // VFILELOCATION_H diff --git a/src/vnote.qrc b/src/vnote.qrc index 3d8babd5..24e857b4 100644 --- a/src/vnote.qrc +++ b/src/vnote.qrc @@ -64,5 +64,8 @@ resources/vnote.qss resources/icons/note_info_tb.svg resources/icons/delete_note_tb.svg + resources/icons/copy.svg + resources/icons/cut.svg + resources/icons/paste.svg