|
|
@@ -47,6 +47,24 @@ void VDirectoryTree::initActions()
|
|
|
dirInfoAct->setStatusTip(tr("View and edit current directory's information"));
|
|
|
connect(dirInfoAct, &QAction::triggered,
|
|
|
this, &VDirectoryTree::editDirectoryInfo);
|
|
|
+
|
|
|
+ copyAct = new QAction(QIcon(":/resources/icons/copy.svg"),
|
|
|
+ tr("&Copy"), this);
|
|
|
+ copyAct->setStatusTip(tr("Copy selected directories"));
|
|
|
+ connect(copyAct, &QAction::triggered,
|
|
|
+ this, &VDirectoryTree::copySelectedDirectories);
|
|
|
+
|
|
|
+ cutAct = new QAction(QIcon(":/resources/icons/cut.svg"),
|
|
|
+ tr("&Cut"), this);
|
|
|
+ cutAct->setStatusTip(tr("Cut selected directories"));
|
|
|
+ connect(cutAct, &QAction::triggered,
|
|
|
+ this, &VDirectoryTree::cutSelectedDirectories);
|
|
|
+
|
|
|
+ pasteAct = new QAction(QIcon(":/resources/icons/paste.svg"),
|
|
|
+ tr("&Paste"), this);
|
|
|
+ pasteAct->setStatusTip(tr("Paste directories"));
|
|
|
+ connect(pasteAct, &QAction::triggered,
|
|
|
+ this, &VDirectoryTree::pasteDirectoriesInCurDir);
|
|
|
}
|
|
|
|
|
|
void VDirectoryTree::setNotebook(VNotebook *p_notebook)
|
|
|
@@ -145,26 +163,38 @@ void VDirectoryTree::updateChildren(QTreeWidgetItem *p_item)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-QVector<QTreeWidgetItem *> VDirectoryTree::updateItemChildrenAdded(QTreeWidgetItem *p_item)
|
|
|
+void VDirectoryTree::updateItemChildren(QTreeWidgetItem *p_item)
|
|
|
{
|
|
|
- QVector<QTreeWidgetItem *> ret;
|
|
|
QPointer<VDirectory> parentDir;
|
|
|
if (p_item) {
|
|
|
parentDir = getVDirectory(p_item);
|
|
|
} else {
|
|
|
parentDir = m_notebook->getRootDir();
|
|
|
}
|
|
|
- const QVector<VDirectory *> &subDirs = parentDir->getSubDirs();
|
|
|
- for (int i = 0; i < subDirs.size(); ++i) {
|
|
|
- int nrChild;
|
|
|
- if (p_item) {
|
|
|
- nrChild = p_item->childCount();
|
|
|
+ const QVector<VDirectory *> &dirs = parentDir->getSubDirs();
|
|
|
+
|
|
|
+ QHash<VDirectory *, QTreeWidgetItem *> itemDirMap;
|
|
|
+ int nrChild = p_item ? p_item->childCount() : topLevelItemCount();
|
|
|
+ for (int i = 0; i < nrChild; ++i) {
|
|
|
+ QTreeWidgetItem *item = p_item ? p_item->child(i) : topLevelItem(i);
|
|
|
+ itemDirMap.insert(getVDirectory(item), item);
|
|
|
+ }
|
|
|
+
|
|
|
+ for (int i = 0; i < dirs.size(); ++i) {
|
|
|
+ VDirectory *dir = dirs[i];
|
|
|
+ QTreeWidgetItem *item = itemDirMap.value(dir, NULL);
|
|
|
+ if (item) {
|
|
|
+ if (p_item) {
|
|
|
+ p_item->removeChild(item);
|
|
|
+ p_item->insertChild(i, item);
|
|
|
+ } else {
|
|
|
+ int topIdx = indexOfTopLevelItem(item);
|
|
|
+ takeTopLevelItem(topIdx);
|
|
|
+ insertTopLevelItem(i, item);
|
|
|
+ }
|
|
|
+ itemDirMap.remove(dir);
|
|
|
} else {
|
|
|
- nrChild = this->topLevelItemCount();
|
|
|
- }
|
|
|
- VDirectory *dir = subDirs[i];
|
|
|
- QTreeWidgetItem *item;
|
|
|
- if (i >= nrChild) {
|
|
|
+ // Insert a new item
|
|
|
if (p_item) {
|
|
|
item = new QTreeWidgetItem(p_item);
|
|
|
} else {
|
|
|
@@ -172,37 +202,30 @@ QVector<QTreeWidgetItem *> VDirectoryTree::updateItemChildrenAdded(QTreeWidgetIt
|
|
|
}
|
|
|
fillTreeItem(*item, dir->getName(), dir, QIcon(":/resources/icons/dir_item.svg"));
|
|
|
updateDirectoryTreeOne(item, 1);
|
|
|
- ret.append(item);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Delete items without corresponding VDirectory
|
|
|
+ for (auto iter = itemDirMap.begin(); iter != itemDirMap.end(); ++iter) {
|
|
|
+ QTreeWidgetItem *item = iter.value();
|
|
|
+ if (p_item) {
|
|
|
+ p_item->removeChild(item);
|
|
|
} else {
|
|
|
- VDirectory *itemDir;
|
|
|
- if (p_item) {
|
|
|
- itemDir = getVDirectory(p_item->child(i));
|
|
|
- } else {
|
|
|
- itemDir = getVDirectory(topLevelItem(i));
|
|
|
- }
|
|
|
- if (itemDir != dir) {
|
|
|
- item = new QTreeWidgetItem();
|
|
|
- if (p_item) {
|
|
|
- p_item->insertChild(i, item);
|
|
|
- } else {
|
|
|
- this->insertTopLevelItem(i, item);
|
|
|
- }
|
|
|
- fillTreeItem(*item, dir->getName(), dir, QIcon(":/resources/icons/dir_item.svg"));
|
|
|
- updateDirectoryTreeOne(item, 1);
|
|
|
- ret.append(item);
|
|
|
- }
|
|
|
+ int topIdx = indexOfTopLevelItem(item);
|
|
|
+ takeTopLevelItem(topIdx);
|
|
|
}
|
|
|
+ delete item;
|
|
|
}
|
|
|
- qDebug() << ret.size() << "items added";
|
|
|
- return ret;
|
|
|
}
|
|
|
|
|
|
void VDirectoryTree::contextMenuRequested(QPoint pos)
|
|
|
{
|
|
|
+ QTreeWidgetItem *item = itemAt(pos);
|
|
|
+
|
|
|
if (!m_notebook) {
|
|
|
return;
|
|
|
}
|
|
|
- QTreeWidgetItem *item = itemAt(pos);
|
|
|
+
|
|
|
QMenu menu(this);
|
|
|
|
|
|
if (!item) {
|
|
|
@@ -219,8 +242,24 @@ void VDirectoryTree::contextMenuRequested(QPoint pos)
|
|
|
menu.addAction(newSubDirAct);
|
|
|
}
|
|
|
menu.addAction(deleteDirAct);
|
|
|
+ menu.addSeparator();
|
|
|
+ menu.addAction(copyAct);
|
|
|
+ menu.addAction(cutAct);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (VUtils::opTypeInClipboard() == ClipboardOpType::CopyDir
|
|
|
+ && !m_copiedDirs.isEmpty()) {
|
|
|
+ if (!item) {
|
|
|
+ menu.addSeparator();
|
|
|
+ }
|
|
|
+ menu.addAction(pasteAct);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (item) {
|
|
|
+ menu.addSeparator();
|
|
|
menu.addAction(dirInfoAct);
|
|
|
}
|
|
|
+
|
|
|
menu.exec(mapToGlobal(pos));
|
|
|
}
|
|
|
|
|
|
@@ -255,9 +294,7 @@ void VDirectoryTree::newSubDirectory()
|
|
|
QMessageBox::Ok, QMessageBox::Ok, this);
|
|
|
return;
|
|
|
}
|
|
|
- QVector<QTreeWidgetItem *> items = updateItemChildrenAdded(curItem);
|
|
|
- Q_ASSERT(items.size() == 1);
|
|
|
- setCurrentItem(items[0]);
|
|
|
+ updateItemChildren(curItem);
|
|
|
}
|
|
|
break;
|
|
|
} while (true);
|
|
|
@@ -288,9 +325,7 @@ void VDirectoryTree::newRootDirectory()
|
|
|
QMessageBox::Ok, QMessageBox::Ok, this);
|
|
|
return;
|
|
|
}
|
|
|
- QVector<QTreeWidgetItem *> items = updateItemChildrenAdded(NULL);
|
|
|
- Q_ASSERT(items.size() == 1);
|
|
|
- setCurrentItem(items[0]);
|
|
|
+ updateItemChildren(NULL);
|
|
|
}
|
|
|
break;
|
|
|
} while (true);
|
|
|
@@ -356,7 +391,172 @@ void VDirectoryTree::editDirectoryInfo()
|
|
|
return;
|
|
|
}
|
|
|
curItem->setText(0, name);
|
|
|
+ emit directoryUpdated(curDir);
|
|
|
}
|
|
|
break;
|
|
|
} while (true);
|
|
|
}
|
|
|
+
|
|
|
+void VDirectoryTree::copySelectedDirectories(bool p_cut)
|
|
|
+{
|
|
|
+ QList<QTreeWidgetItem *> items = selectedItems();
|
|
|
+ if (items.isEmpty()) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ QJsonArray dirs;
|
|
|
+ m_copiedDirs.clear();
|
|
|
+ for (int i = 0; i < items.size(); ++i) {
|
|
|
+ VDirectory *dir = getVDirectory(items[i]);
|
|
|
+ QJsonObject dirJson;
|
|
|
+ dirJson["notebook"] = dir->getNotebook();
|
|
|
+ dirJson["path"] = dir->retrivePath();
|
|
|
+ dirs.append(dirJson);
|
|
|
+
|
|
|
+ m_copiedDirs.append(dir);
|
|
|
+ }
|
|
|
+
|
|
|
+ copyDirectoryInfoToClipboard(dirs, p_cut);
|
|
|
+}
|
|
|
+
|
|
|
+void VDirectoryTree::copyDirectoryInfoToClipboard(const QJsonArray &p_dirs, bool p_cut)
|
|
|
+{
|
|
|
+ QJsonObject clip;
|
|
|
+ clip["operation"] = (int)ClipboardOpType::CopyDir;
|
|
|
+ clip["is_cut"] = p_cut;
|
|
|
+ clip["sources"] = p_dirs;
|
|
|
+
|
|
|
+ QClipboard *clipboard = QApplication::clipboard();
|
|
|
+ clipboard->setText(QJsonDocument(clip).toJson(QJsonDocument::Compact));
|
|
|
+}
|
|
|
+
|
|
|
+void VDirectoryTree::cutSelectedDirectories()
|
|
|
+{
|
|
|
+ copySelectedDirectories(true);
|
|
|
+}
|
|
|
+
|
|
|
+void VDirectoryTree::pasteDirectoriesInCurDir()
|
|
|
+{
|
|
|
+ QTreeWidgetItem *item = currentItem();
|
|
|
+ VDirectory *destDir = m_notebook->getRootDir();
|
|
|
+ if (item) {
|
|
|
+ destDir = getVDirectory(item);
|
|
|
+ }
|
|
|
+ pasteDirectories(destDir);
|
|
|
+}
|
|
|
+
|
|
|
+void VDirectoryTree::pasteDirectories(VDirectory *p_destDir)
|
|
|
+{
|
|
|
+ QClipboard *clipboard = QApplication::clipboard();
|
|
|
+ QString text = clipboard->text();
|
|
|
+ QJsonObject clip = QJsonDocument::fromJson(text.toLocal8Bit()).object();
|
|
|
+ Q_ASSERT(!clip.isEmpty() && clip["operation"] == (int)ClipboardOpType::CopyDir);
|
|
|
+ bool isCut = clip["is_cut"].toBool();
|
|
|
+
|
|
|
+ int nrPasted = 0;
|
|
|
+ for (int i = 0; i < m_copiedDirs.size(); ++i) {
|
|
|
+ QPointer<VDirectory> srcDir = m_copiedDirs[i];
|
|
|
+ if (!srcDir) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ QString dirName = srcDir->getName();
|
|
|
+ VDirectory *srcParentDir = srcDir->getParentDirectory();
|
|
|
+ if (srcParentDir == p_destDir && !isCut) {
|
|
|
+ // Copy and paste in the same directory.
|
|
|
+ // Rename it to xx_copy
|
|
|
+ dirName = VUtils::generateCopiedDirName(srcParentDir->retrivePath(), dirName);
|
|
|
+ }
|
|
|
+ if (copyDirectory(p_destDir, dirName, srcDir, isCut)) {
|
|
|
+ nrPasted++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ qDebug() << "pasted" << nrPasted << "files successfully";
|
|
|
+ clipboard->clear();
|
|
|
+ m_copiedDirs.clear();
|
|
|
+}
|
|
|
+
|
|
|
+void VDirectoryTree::mousePressEvent(QMouseEvent *event)
|
|
|
+{
|
|
|
+ QTreeWidgetItem *item = itemAt(event->pos());
|
|
|
+ if (!item) {
|
|
|
+ setCurrentItem(NULL);
|
|
|
+ }
|
|
|
+ QTreeWidget::mousePressEvent(event);
|
|
|
+}
|
|
|
+
|
|
|
+bool VDirectoryTree::copyDirectory(VDirectory *p_destDir, const QString &p_destName,
|
|
|
+ VDirectory *p_srcDir, bool p_cut)
|
|
|
+{
|
|
|
+ qDebug() << "copy" << p_srcDir->getName() << "to" << p_destDir->getName()
|
|
|
+ << "as" << p_destName;
|
|
|
+ QString srcName = p_srcDir->getName();
|
|
|
+ QString srcPath = QDir::cleanPath(p_srcDir->retrivePath());
|
|
|
+ QString destPath = QDir::cleanPath(QDir(p_destDir->retrivePath()).filePath(p_destName));
|
|
|
+ if (srcPath == destPath) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ VDirectory *srcParentDir = p_srcDir->getParentDirectory();
|
|
|
+ VDirectory *destDir = VDirectory::copyDirectory(p_destDir, p_destName, p_srcDir, p_cut);
|
|
|
+
|
|
|
+ if (destDir) {
|
|
|
+ // Update QTreeWidget
|
|
|
+ bool isWidget;
|
|
|
+ QTreeWidgetItem *destItem = findVDirectory(p_destDir, isWidget);
|
|
|
+ if (destItem || isWidget) {
|
|
|
+ updateItemChildren(destItem);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (p_cut) {
|
|
|
+ QTreeWidgetItem *srcItem = findVDirectory(srcParentDir, isWidget);
|
|
|
+ if (srcItem || isWidget) {
|
|
|
+ updateItemChildren(srcItem);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Broadcast this update
|
|
|
+ emit directoryUpdated(destDir);
|
|
|
+ } else {
|
|
|
+ VUtils::showMessage(QMessageBox::Warning, tr("Warning"),
|
|
|
+ QString("Failed to copy directory %1.").arg(srcName),
|
|
|
+ QString("Please check if there alread exists a directory with the same name"),
|
|
|
+ QMessageBox::Ok, QMessageBox::Ok, this);
|
|
|
+ }
|
|
|
+
|
|
|
+ return destDir;
|
|
|
+}
|
|
|
+
|
|
|
+QTreeWidgetItem *VDirectoryTree::findVDirectory(const VDirectory *p_dir, bool &p_widget)
|
|
|
+{
|
|
|
+ p_widget = false;
|
|
|
+ if (!p_dir) {
|
|
|
+ return NULL;
|
|
|
+ } else if (p_dir->getNotebook() != m_notebook->getName()) {
|
|
|
+ return NULL;
|
|
|
+ } else if (p_dir == m_notebook->getRootDir()) {
|
|
|
+ p_widget = true;
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ bool isWidget;
|
|
|
+ QTreeWidgetItem *pItem = findVDirectory(p_dir->getParentDirectory(), isWidget);
|
|
|
+ if (pItem) {
|
|
|
+ // Iterate all its children to find the match.
|
|
|
+ int nrChild = pItem->childCount();
|
|
|
+ for (int i = 0; i < nrChild; ++i) {
|
|
|
+ QTreeWidgetItem *item = pItem->child(i);
|
|
|
+ if (getVDirectory(item) == p_dir) {
|
|
|
+ return item;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else if (isWidget) {
|
|
|
+ // Iterate all the top-level items.
|
|
|
+ int nrChild = topLevelItemCount();
|
|
|
+ for (int i = 0; i < nrChild; ++i) {
|
|
|
+ QTreeWidgetItem *item = topLevelItem(i);
|
|
|
+ if (getVDirectory(item) == p_dir) {
|
|
|
+ return item;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return NULL;
|
|
|
+}
|