vdirectorytree.cpp 42 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325
  1. #include <QtWidgets>
  2. #include "vdirectorytree.h"
  3. #include "dialog/vnewdirdialog.h"
  4. #include "vconfigmanager.h"
  5. #include "dialog/vdirinfodialog.h"
  6. #include "vnote.h"
  7. #include "vdirectory.h"
  8. #include "utils/vutils.h"
  9. #include "veditarea.h"
  10. #include "vconfigmanager.h"
  11. #include "vmainwindow.h"
  12. #include "dialog/vsortdialog.h"
  13. #include "utils/vimnavigationforwidget.h"
  14. #include "utils/viconutils.h"
  15. #include "vfilelist.h"
  16. #include "vhistorylist.h"
  17. extern VMainWindow *g_mainWin;
  18. extern VConfigManager *g_config;
  19. extern VNote *g_vnote;
  20. VDirectoryTree::VDirectoryTree(QWidget *parent)
  21. : VTreeWidget(parent),
  22. VNavigationMode(),
  23. m_editArea(NULL)
  24. {
  25. setColumnCount(1);
  26. setHeaderHidden(true);
  27. setContextMenuPolicy(Qt::CustomContextMenu);
  28. setFitContent(true);
  29. viewport()->setAcceptDrops(true);
  30. setDropIndicatorShown(true);
  31. initShortcuts();
  32. connect(this, SIGNAL(itemExpanded(QTreeWidgetItem*)),
  33. this, SLOT(handleItemExpanded(QTreeWidgetItem*)));
  34. connect(this, SIGNAL(itemCollapsed(QTreeWidgetItem*)),
  35. this, SLOT(handleItemCollapsed(QTreeWidgetItem*)));
  36. connect(this, SIGNAL(customContextMenuRequested(QPoint)),
  37. this, SLOT(contextMenuRequested(QPoint)));
  38. connect(this, &VDirectoryTree::currentItemChanged,
  39. this, &VDirectoryTree::currentDirectoryItemChanged);
  40. }
  41. void VDirectoryTree::initShortcuts()
  42. {
  43. QShortcut *infoShortcut = new QShortcut(QKeySequence(Shortcut::c_info), this);
  44. infoShortcut->setContext(Qt::WidgetWithChildrenShortcut);
  45. connect(infoShortcut, &QShortcut::activated,
  46. this, [this](){
  47. editDirectoryInfo();
  48. });
  49. QShortcut *copyShortcut = new QShortcut(QKeySequence(Shortcut::c_copy), this);
  50. copyShortcut->setContext(Qt::WidgetWithChildrenShortcut);
  51. connect(copyShortcut, &QShortcut::activated,
  52. this, [this](){
  53. copySelectedDirectories();
  54. });
  55. QShortcut *cutShortcut = new QShortcut(QKeySequence(Shortcut::c_cut), this);
  56. cutShortcut->setContext(Qt::WidgetWithChildrenShortcut);
  57. connect(cutShortcut, &QShortcut::activated,
  58. this, [this](){
  59. cutSelectedDirectories();
  60. });
  61. QShortcut *pasteShortcut = new QShortcut(QKeySequence(Shortcut::c_paste), this);
  62. pasteShortcut->setContext(Qt::WidgetWithChildrenShortcut);
  63. connect(pasteShortcut, &QShortcut::activated,
  64. this, [this](){
  65. pasteDirectoriesFromClipboard();
  66. });
  67. QKeySequence seq = QKeySequence(g_config->getShortcutKeySequence("NewSubfolder"));
  68. if (!seq.isEmpty()) {
  69. QShortcut *newSubDirShortcut = new QShortcut(seq, this);
  70. newSubDirShortcut->setContext(Qt::ApplicationShortcut);
  71. connect(newSubDirShortcut, &QShortcut::activated,
  72. this, [this](){
  73. newSubDirectory();
  74. });
  75. }
  76. }
  77. void VDirectoryTree::setNotebook(VNotebook *p_notebook)
  78. {
  79. if (m_notebook == p_notebook) {
  80. return;
  81. }
  82. clear();
  83. m_notebook = p_notebook;
  84. if (!m_notebook) {
  85. return;
  86. }
  87. if (!m_notebook->open()) {
  88. VUtils::showMessage(QMessageBox::Warning,
  89. tr("Warning"),
  90. tr("Fail to open notebook <span style=\"%1\">%2</span>.")
  91. .arg(g_config->c_dataTextStyle)
  92. .arg(m_notebook->getName()),
  93. tr("Please check if the notebook's root folder <span style=\"%1\">%2</span> exists.")
  94. .arg(g_config->c_dataTextStyle)
  95. .arg(m_notebook->getPath()),
  96. QMessageBox::Ok,
  97. QMessageBox::Ok,
  98. this);
  99. return;
  100. }
  101. updateDirectoryTree();
  102. }
  103. void VDirectoryTree::fillTreeItem(QTreeWidgetItem *p_item, VDirectory *p_directory)
  104. {
  105. static QIcon itemIcon = VIconUtils::treeViewIcon(":/resources/icons/dir_item.svg");
  106. int col = 0;
  107. QString name = p_directory->getName();
  108. p_item->setText(col, name);
  109. p_item->setToolTip(col, name);
  110. p_item->setData(col, Qt::UserRole, QVariant::fromValue(p_directory));
  111. p_item->setIcon(col, itemIcon);
  112. }
  113. void VDirectoryTree::updateDirectoryTree()
  114. {
  115. clear();
  116. VDirectory *rootDir = m_notebook->getRootDir();
  117. const QVector<VDirectory *> &subDirs = rootDir->getSubDirs();
  118. for (int i = 0; i < subDirs.size(); ++i) {
  119. VDirectory *dir = subDirs[i];
  120. QTreeWidgetItem *item = new QTreeWidgetItem(this);
  121. fillTreeItem(item, dir);
  122. buildSubTree(item, 1);
  123. }
  124. if (!restoreCurrentItem() && topLevelItemCount() > 0) {
  125. setCurrentItem(topLevelItem(0));
  126. }
  127. resizeColumnToContents(0);
  128. }
  129. bool VDirectoryTree::restoreCurrentItem()
  130. {
  131. auto it = m_notebookCurrentDirMap.find(m_notebook);
  132. if (it != m_notebookCurrentDirMap.end()) {
  133. QTreeWidgetItem *item = findVDirectory(it.value());
  134. if (item) {
  135. setCurrentItem(item);
  136. return true;
  137. }
  138. }
  139. return false;
  140. }
  141. void VDirectoryTree::buildSubTree(QTreeWidgetItem *p_parent, int p_depth)
  142. {
  143. if (p_depth == 0) {
  144. return;
  145. }
  146. Q_ASSERT(p_parent);
  147. VDirectory *dir = getVDirectory(p_parent);
  148. if (!dir->open()) {
  149. VUtils::showMessage(QMessageBox::Warning,
  150. tr("Warning"),
  151. tr("Fail to open folder <span style=\"%1\">%2</span>.")
  152. .arg(g_config->c_dataTextStyle)
  153. .arg(dir->getName()),
  154. tr("Please check if directory <span style=\"%1\">%2</span> exists.")
  155. .arg(g_config->c_dataTextStyle)
  156. .arg(dir->fetchPath()),
  157. QMessageBox::Ok,
  158. QMessageBox::Ok,
  159. this);
  160. return;
  161. }
  162. if (p_parent->childCount() > 0) {
  163. // This directory has been built before. Try its children directly.
  164. int cnt = p_parent->childCount();
  165. for (int i = 0; i < cnt; ++i) {
  166. buildSubTree(p_parent->child(i), p_depth -1);
  167. }
  168. } else {
  169. const QVector<VDirectory *> &subDirs = dir->getSubDirs();
  170. for (int i = 0; i < subDirs.size(); ++i) {
  171. VDirectory *subDir = subDirs[i];
  172. QTreeWidgetItem *item = new QTreeWidgetItem(p_parent);
  173. fillTreeItem(item, subDir);
  174. buildSubTree(item, p_depth - 1);
  175. }
  176. }
  177. if (dir->isExpanded()) {
  178. expandItem(p_parent);
  179. }
  180. }
  181. void VDirectoryTree::handleItemCollapsed(QTreeWidgetItem *p_item)
  182. {
  183. if (p_item) {
  184. VDirectory *dir = getVDirectory(p_item);
  185. dir->setExpanded(false);
  186. }
  187. }
  188. void VDirectoryTree::handleItemExpanded(QTreeWidgetItem *p_item)
  189. {
  190. if (p_item) {
  191. buildChildren(p_item);
  192. VDirectory *dir = getVDirectory(p_item);
  193. dir->setExpanded(true);
  194. }
  195. }
  196. void VDirectoryTree::buildChildren(QTreeWidgetItem *p_item)
  197. {
  198. Q_ASSERT(p_item);
  199. int nrChild = p_item->childCount();
  200. if (nrChild == 0) {
  201. return;
  202. }
  203. for (int i = 0; i < nrChild; ++i) {
  204. QTreeWidgetItem *childItem = p_item->child(i);
  205. if (childItem->childCount() > 0) {
  206. continue;
  207. }
  208. buildSubTree(childItem, 1);
  209. }
  210. }
  211. void VDirectoryTree::updateItemDirectChildren(QTreeWidgetItem *p_item)
  212. {
  213. QPointer<VDirectory> parentDir;
  214. if (p_item) {
  215. parentDir = getVDirectory(p_item);
  216. } else {
  217. parentDir = m_notebook->getRootDir();
  218. }
  219. const QVector<VDirectory *> &dirs = parentDir->getSubDirs();
  220. QHash<VDirectory *, QTreeWidgetItem *> itemDirMap;
  221. int nrChild = p_item ? p_item->childCount() : topLevelItemCount();
  222. for (int i = 0; i < nrChild; ++i) {
  223. QTreeWidgetItem *item = p_item ? p_item->child(i) : topLevelItem(i);
  224. itemDirMap.insert(getVDirectory(item), item);
  225. }
  226. for (int i = 0; i < dirs.size(); ++i) {
  227. VDirectory *dir = dirs[i];
  228. QTreeWidgetItem *item = itemDirMap.value(dir, NULL);
  229. if (item) {
  230. if (p_item) {
  231. p_item->removeChild(item);
  232. p_item->insertChild(i, item);
  233. } else {
  234. int topIdx = indexOfTopLevelItem(item);
  235. takeTopLevelItem(topIdx);
  236. insertTopLevelItem(i, item);
  237. }
  238. itemDirMap.remove(dir);
  239. } else {
  240. // Insert a new item
  241. if (p_item) {
  242. item = new QTreeWidgetItem(p_item);
  243. } else {
  244. item = new QTreeWidgetItem(this);
  245. }
  246. fillTreeItem(item, dir);
  247. buildSubTree(item, 1);
  248. }
  249. expandSubTree(item);
  250. }
  251. // Delete items without corresponding VDirectory
  252. for (auto iter = itemDirMap.begin(); iter != itemDirMap.end(); ++iter) {
  253. QTreeWidgetItem *item = iter.value();
  254. if (p_item) {
  255. p_item->removeChild(item);
  256. } else {
  257. int topIdx = indexOfTopLevelItem(item);
  258. takeTopLevelItem(topIdx);
  259. }
  260. delete item;
  261. }
  262. }
  263. void VDirectoryTree::contextMenuRequested(QPoint pos)
  264. {
  265. QTreeWidgetItem *item = itemAt(pos);
  266. if (!m_notebook) {
  267. return;
  268. }
  269. QMenu menu(this);
  270. menu.setToolTipsVisible(true);
  271. QAction *newRootDirAct = new QAction(VIconUtils::menuIcon(":/resources/icons/create_rootdir.svg"),
  272. tr("New &Root Folder"),
  273. &menu);
  274. newRootDirAct->setToolTip(tr("Create a root folder in current notebook"));
  275. connect(newRootDirAct, &QAction::triggered,
  276. this, &VDirectoryTree::newRootDirectory);
  277. QAction *sortAct = new QAction(VIconUtils::menuIcon(":/resources/icons/sort.svg"),
  278. tr("&Sort"),
  279. &menu);
  280. sortAct->setToolTip(tr("Sort folders in this folder/notebook manually"));
  281. connect(sortAct, SIGNAL(triggered(bool)),
  282. this, SLOT(sortItems()));
  283. if (!item) {
  284. // Context menu on the free space of the QTreeWidget
  285. menu.addAction(newRootDirAct);
  286. if (topLevelItemCount() > 1) {
  287. menu.addAction(sortAct);
  288. }
  289. } else {
  290. // Context menu on a QTreeWidgetItem
  291. QAction *newNoteAct = new QAction(VIconUtils::menuIcon(":/resources/icons/create_note_tb.svg"),
  292. tr("New &Note"),
  293. &menu);
  294. VUtils::fixTextWithShortcut(newNoteAct, "NewNote");
  295. newNoteAct->setToolTip(tr("Create a note in selected folder"));
  296. connect(newNoteAct, &QAction::triggered,
  297. this, []() {
  298. g_mainWin->getFileList()->newFile();
  299. });
  300. menu.addAction(newNoteAct);
  301. QAction *newSiblingFolder = new QAction(tr("New Si&bling Folder"), &menu);
  302. newSiblingFolder->setToolTip(tr("Create a folder in the same parent folder"));
  303. connect(newSiblingFolder, &QAction::triggered,
  304. this, [this]() {
  305. auto item = currentItem();
  306. if (item) {
  307. newDirectory(item->parent());
  308. }
  309. });
  310. QAction *newSubDirAct = new QAction(VIconUtils::menuIcon(":/resources/icons/create_subdir.svg"),
  311. tr("New Sub&folder"),
  312. &menu);
  313. newSubDirAct->setToolTip(tr("Create a subfolder"));
  314. VUtils::fixTextWithShortcut(newSubDirAct, "NewSubfolder");
  315. connect(newSubDirAct, &QAction::triggered,
  316. this, &VDirectoryTree::newSubDirectory);
  317. if (item->parent()) {
  318. // Low-level item
  319. menu.addAction(newSiblingFolder);
  320. menu.addAction(newSubDirAct);
  321. if (item->parent()->childCount() > 1) {
  322. menu.addAction(sortAct);
  323. }
  324. } else {
  325. // Top-level item
  326. menu.addAction(newRootDirAct);
  327. menu.addAction(newSubDirAct);
  328. if (topLevelItemCount() > 1) {
  329. menu.addAction(sortAct);
  330. }
  331. }
  332. menu.addSeparator();
  333. QAction *deleteDirAct = new QAction(VIconUtils::menuDangerIcon(":/resources/icons/delete_dir.svg"),
  334. tr("&Delete"),
  335. &menu);
  336. deleteDirAct->setToolTip(tr("Delete selected folder"));
  337. connect(deleteDirAct, &QAction::triggered,
  338. this, &VDirectoryTree::deleteSelectedDirectory);
  339. menu.addAction(deleteDirAct);
  340. QAction *copyAct = new QAction(VIconUtils::menuIcon(":/resources/icons/copy.svg"),
  341. tr("&Copy\t%1").arg(VUtils::getShortcutText(Shortcut::c_copy)),
  342. &menu);
  343. copyAct->setToolTip(tr("Copy selected folders"));
  344. connect(copyAct, &QAction::triggered,
  345. this, &VDirectoryTree::copySelectedDirectories);
  346. menu.addAction(copyAct);
  347. QAction *cutAct = new QAction(VIconUtils::menuIcon(":/resources/icons/cut.svg"),
  348. tr("C&ut\t%1").arg(VUtils::getShortcutText(Shortcut::c_cut)),
  349. &menu);
  350. cutAct->setToolTip(tr("Cut selected folders"));
  351. connect(cutAct, &QAction::triggered,
  352. this, &VDirectoryTree::cutSelectedDirectories);
  353. menu.addAction(cutAct);
  354. }
  355. if (pasteAvailable()) {
  356. if (!item) {
  357. menu.addSeparator();
  358. }
  359. QAction *pasteAct = new QAction(VIconUtils::menuIcon(":/resources/icons/paste.svg"),
  360. tr("&Paste\t%1").arg(VUtils::getShortcutText(Shortcut::c_paste)),
  361. &menu);
  362. pasteAct->setToolTip(tr("Paste folders in this folder"));
  363. connect(pasteAct, &QAction::triggered,
  364. this, &VDirectoryTree::pasteDirectoriesFromClipboard);
  365. menu.addAction(pasteAct);
  366. }
  367. menu.addSeparator();
  368. QAction *reloadAct = new QAction(tr("Reload From Disk"), &menu);
  369. reloadAct->setToolTip(tr("Reload the content of this folder (or notebook) from disk"));
  370. connect(reloadAct, &QAction::triggered,
  371. this, &VDirectoryTree::reloadFromDisk);
  372. menu.addAction(reloadAct);
  373. if (item) {
  374. QAction *openLocationAct = new QAction(VIconUtils::menuIcon(":/resources/icons/open_location.svg"),
  375. tr("Open Folder &Location"),
  376. &menu);
  377. openLocationAct->setToolTip(tr("Explore this folder in operating system"));
  378. connect(openLocationAct, &QAction::triggered,
  379. this, &VDirectoryTree::openDirectoryLocation);
  380. menu.addAction(openLocationAct);
  381. QAction *pinToHistoryAct = new QAction(VIconUtils::menuIcon(":/resources/icons/pin.svg"),
  382. tr("Pin To History"),
  383. &menu);
  384. pinToHistoryAct->setToolTip(tr("Pin selected folder to History"));
  385. connect(pinToHistoryAct, &QAction::triggered,
  386. this, &VDirectoryTree::pinDirectoryToHistory);
  387. menu.addAction(pinToHistoryAct);
  388. QAction *dirInfoAct = new QAction(VIconUtils::menuIcon(":/resources/icons/dir_info.svg"),
  389. tr("&Info (Rename)\t%1").arg(VUtils::getShortcutText(Shortcut::c_info)),
  390. &menu);
  391. dirInfoAct->setToolTip(tr("View and edit current folder's information"));
  392. connect(dirInfoAct, &QAction::triggered,
  393. this, &VDirectoryTree::editDirectoryInfo);
  394. menu.addAction(dirInfoAct);
  395. }
  396. menu.exec(mapToGlobal(pos));
  397. }
  398. void VDirectoryTree::newSubDirectory()
  399. {
  400. if (!m_notebook) {
  401. return;
  402. }
  403. newDirectory(currentItem());
  404. }
  405. void VDirectoryTree::newDirectory(QTreeWidgetItem *p_parentItem)
  406. {
  407. if (!p_parentItem) {
  408. return;
  409. }
  410. VDirectory *curDir = getVDirectory(p_parentItem);
  411. QString info = tr("Create a subfolder in <span style=\"%1\">%2</span>.")
  412. .arg(g_config->c_dataTextStyle)
  413. .arg(curDir->getName());
  414. QString defaultName("new_folder");
  415. defaultName = VUtils::getDirNameWithSequence(curDir->fetchPath(), defaultName);
  416. VNewDirDialog dialog(tr("Create Folder"), info, defaultName, curDir, this);
  417. if (dialog.exec() == QDialog::Accepted) {
  418. QString name = dialog.getNameInput();
  419. QString msg;
  420. VDirectory *subDir = curDir->createSubDirectory(name, &msg);
  421. if (!subDir) {
  422. VUtils::showMessage(QMessageBox::Warning,
  423. tr("Warning"),
  424. tr("Fail to create subfolder <span style=\"%1\">%2</span>.")
  425. .arg(g_config->c_dataTextStyle)
  426. .arg(name),
  427. msg,
  428. QMessageBox::Ok,
  429. QMessageBox::Ok,
  430. this);
  431. return;
  432. }
  433. updateItemDirectChildren(p_parentItem);
  434. locateDirectory(subDir);
  435. }
  436. }
  437. void VDirectoryTree::newRootDirectory()
  438. {
  439. if (!m_notebook) {
  440. return;
  441. }
  442. VDirectory *rootDir = m_notebook->getRootDir();
  443. QString info = tr("Create a root folder in notebook <span style=\"%1\">%2</span>.")
  444. .arg(g_config->c_dataTextStyle)
  445. .arg(m_notebook->getName());
  446. QString defaultName("new_folder");
  447. defaultName = VUtils::getDirNameWithSequence(rootDir->fetchPath(), defaultName);
  448. VNewDirDialog dialog(tr("Create Root Folder"), info, defaultName, rootDir, this);
  449. if (dialog.exec() == QDialog::Accepted) {
  450. QString name = dialog.getNameInput();
  451. QString msg;
  452. VDirectory *dir = rootDir->createSubDirectory(name, &msg);
  453. if (!dir) {
  454. VUtils::showMessage(QMessageBox::Warning,
  455. tr("Warning"),
  456. tr("Fail to create root folder <span style=\"%1\">%2</span>.")
  457. .arg(g_config->c_dataTextStyle)
  458. .arg(name),
  459. msg,
  460. QMessageBox::Ok,
  461. QMessageBox::Ok,
  462. this);
  463. return;
  464. }
  465. updateItemDirectChildren(NULL);
  466. locateDirectory(dir);
  467. }
  468. }
  469. void VDirectoryTree::deleteSelectedDirectory()
  470. {
  471. Q_ASSERT(selectedItems().size() <= 1);
  472. QTreeWidgetItem *curItem = currentItem();
  473. if (!curItem) {
  474. return;
  475. }
  476. VDirectory *curDir = getVDirectory(curItem);
  477. int ret = VUtils::showMessage(QMessageBox::Warning,
  478. tr("Warning"),
  479. tr("Are you sure to delete folder <span style=\"%1\">%2</span>?")
  480. .arg(g_config->c_dataTextStyle)
  481. .arg(curDir->getName()),
  482. tr("<span style=\"%1\">WARNING</span>: "
  483. "VNote will delete the whole directory "
  484. "<span style=\"%2\">%3</span>."
  485. "Deleted files could be found in the recycle bin "
  486. "of this folder.<br>"
  487. "The operation is IRREVERSIBLE!")
  488. .arg(g_config->c_warningTextStyle)
  489. .arg(g_config->c_dataTextStyle)
  490. .arg(curDir->fetchPath()),
  491. QMessageBox::Ok | QMessageBox::Cancel,
  492. QMessageBox::Ok,
  493. this,
  494. MessageBoxType::Danger);
  495. if (ret == QMessageBox::Ok) {
  496. int nrDeleted = 1;
  497. m_editArea->closeFile(curDir, true);
  498. // Remove the item from the tree.
  499. delete curItem;
  500. QString msg;
  501. QString dirName = curDir->getName();
  502. QString dirPath = curDir->fetchPath();
  503. if (!VDirectory::deleteDirectory(curDir, false, &msg)) {
  504. VUtils::showMessage(QMessageBox::Warning,
  505. tr("Warning"),
  506. tr("Fail to delete folder <span style=\"%1\">%2</span>.<br>"
  507. "Please check <span style=\"%1\">%3</span> and manually delete it.")
  508. .arg(g_config->c_dataTextStyle)
  509. .arg(dirName)
  510. .arg(dirPath),
  511. msg,
  512. QMessageBox::Ok,
  513. QMessageBox::Ok,
  514. this);
  515. } else {
  516. g_mainWin->showStatusMessage(tr("%1 %2 deleted")
  517. .arg(nrDeleted)
  518. .arg(nrDeleted > 1 ? tr("folders") : tr("folder")));
  519. }
  520. }
  521. }
  522. void VDirectoryTree::currentDirectoryItemChanged(QTreeWidgetItem *currentItem)
  523. {
  524. if (!currentItem) {
  525. emit currentDirectoryChanged(NULL);
  526. return;
  527. }
  528. QPointer<VDirectory> dir = getVDirectory(currentItem);
  529. m_notebookCurrentDirMap[m_notebook] = dir;
  530. emit currentDirectoryChanged(dir);
  531. }
  532. void VDirectoryTree::editDirectoryInfo()
  533. {
  534. QTreeWidgetItem *curItem = currentItem();
  535. if (!curItem) {
  536. return;
  537. }
  538. VDirectory *curDir = getVDirectory(curItem);
  539. QString curName = curDir->getName();
  540. VDirInfoDialog dialog(tr("Folder Information"),
  541. "",
  542. curDir,
  543. curDir->getParentDirectory(),
  544. this);
  545. if (dialog.exec() == QDialog::Accepted) {
  546. QString name = dialog.getNameInput();
  547. if (name == curName) {
  548. return;
  549. }
  550. if (!curDir->rename(name)) {
  551. VUtils::showMessage(QMessageBox::Warning,
  552. tr("Warning"),
  553. tr("Fail to rename folder <span style=\"%1\">%2</span>.")
  554. .arg(g_config->c_dataTextStyle)
  555. .arg(curName),
  556. "",
  557. QMessageBox::Ok,
  558. QMessageBox::Ok,
  559. this);
  560. return;
  561. }
  562. fillTreeItem(curItem, curDir);
  563. emit directoryUpdated(curDir, UpdateAction::InfoChanged);
  564. }
  565. }
  566. void VDirectoryTree::openDirectoryLocation() const
  567. {
  568. QTreeWidgetItem *curItem = currentItem();
  569. V_ASSERT(curItem);
  570. QUrl url = QUrl::fromLocalFile(getVDirectory(curItem)->fetchPath());
  571. QDesktopServices::openUrl(url);
  572. }
  573. void VDirectoryTree::reloadFromDisk()
  574. {
  575. if (!m_notebook) {
  576. return;
  577. }
  578. QString msg;
  579. QString info;
  580. VDirectory *curDir = NULL;
  581. QTreeWidgetItem *curItem = currentItem();
  582. if (curItem) {
  583. // Reload current directory.
  584. curDir = getVDirectory(curItem);
  585. info = tr("Are you sure to reload folder <span style=\"%1\">%2</span>?")
  586. .arg(g_config->c_dataTextStyle).arg(curDir->getName());
  587. msg = tr("Folder %1 reloaded from disk").arg(curDir->getName());
  588. } else {
  589. // Reload notebook.
  590. info = tr("Are you sure to reload notebook <span style=\"%1\">%2</span>?")
  591. .arg(g_config->c_dataTextStyle).arg(m_notebook->getName());
  592. msg = tr("Notebook %1 reloaded from disk").arg(m_notebook->getName());
  593. }
  594. if (g_config->getConfirmReloadFolder()) {
  595. int ret = VUtils::showMessage(QMessageBox::Information, tr("Information"),
  596. info,
  597. tr("VNote will close all the related notes before reload."),
  598. QMessageBox::Ok | QMessageBox::YesToAll | QMessageBox::Cancel,
  599. QMessageBox::Ok,
  600. this);
  601. switch (ret) {
  602. case QMessageBox::YesToAll:
  603. g_config->setConfirmReloadFolder(false);
  604. // Fall through.
  605. case QMessageBox::Ok:
  606. break;
  607. case QMessageBox::Cancel:
  608. return;
  609. default:
  610. return;
  611. }
  612. }
  613. m_notebookCurrentDirMap.remove(m_notebook);
  614. if (curItem) {
  615. if (!m_editArea->closeFile(curDir, false)) {
  616. return;
  617. }
  618. setCurrentItem(NULL);
  619. curItem->setExpanded(false);
  620. curDir->setExpanded(false);
  621. curDir->close();
  622. // Remove all its children.
  623. QList<QTreeWidgetItem *> children = curItem->takeChildren();
  624. for (int i = 0; i < children.size(); ++i) {
  625. delete children[i];
  626. }
  627. buildSubTree(curItem, 1);
  628. setCurrentItem(curItem);
  629. } else {
  630. if (!m_editArea->closeFile(m_notebook, false)) {
  631. return;
  632. }
  633. m_notebook->close();
  634. if (!m_notebook->open()) {
  635. VUtils::showMessage(QMessageBox::Warning, tr("Warning"),
  636. tr("Fail to open notebook <span style=\"%1\">%2</span>.")
  637. .arg(g_config->c_dataTextStyle).arg(m_notebook->getName()),
  638. tr("Please check if path <span style=\"%1\">%2</span> exists.")
  639. .arg(g_config->c_dataTextStyle).arg(m_notebook->getPath()),
  640. QMessageBox::Ok, QMessageBox::Ok, this);
  641. clear();
  642. return;
  643. }
  644. updateDirectoryTree();
  645. }
  646. if (!msg.isEmpty()) {
  647. g_mainWin->showStatusMessage(msg);
  648. }
  649. }
  650. void VDirectoryTree::copySelectedDirectories(bool p_isCut)
  651. {
  652. QList<QTreeWidgetItem *> items = selectedItems();
  653. if (items.isEmpty()) {
  654. return;
  655. }
  656. QJsonArray dirs;
  657. for (int i = 0; i < items.size(); ++i) {
  658. VDirectory *dir = getVDirectory(items[i]);
  659. dirs.append(dir->fetchPath());
  660. }
  661. QJsonObject clip;
  662. clip[ClipboardConfig::c_magic] = getNewMagic();
  663. clip[ClipboardConfig::c_type] = (int)ClipboardOpType::CopyDir;
  664. clip[ClipboardConfig::c_isCut] = p_isCut;
  665. clip[ClipboardConfig::c_dirs] = dirs;
  666. QClipboard *clipboard = QApplication::clipboard();
  667. clipboard->setText(QJsonDocument(clip).toJson(QJsonDocument::Compact));
  668. qDebug() << "copied directories info" << clipboard->text();
  669. int cnt = dirs.size();
  670. g_mainWin->showStatusMessage(tr("%1 %2 %3")
  671. .arg(cnt)
  672. .arg(cnt > 1 ? tr("folders") : tr("folder"))
  673. .arg(p_isCut ? tr("cut") : tr("copied")));
  674. }
  675. void VDirectoryTree::cutSelectedDirectories()
  676. {
  677. copySelectedDirectories(true);
  678. }
  679. void VDirectoryTree::pasteDirectoriesFromClipboard()
  680. {
  681. if (!pasteAvailable()) {
  682. return;
  683. }
  684. QJsonObject obj = VUtils::clipboardToJson();
  685. QJsonArray dirs = obj[ClipboardConfig::c_dirs].toArray();
  686. bool isCut = obj[ClipboardConfig::c_isCut].toBool();
  687. QVector<QString> dirsToPaste(dirs.size());
  688. for (int i = 0; i < dirs.size(); ++i) {
  689. dirsToPaste[i] = dirs[i].toString();
  690. }
  691. VDirectory *destDir;
  692. QTreeWidgetItem *item = currentItem();
  693. if (item) {
  694. destDir = getVDirectory(item);
  695. } else {
  696. destDir = m_notebook->getRootDir();
  697. }
  698. pasteDirectories(destDir, dirsToPaste, isCut);
  699. QClipboard *clipboard = QApplication::clipboard();
  700. clipboard->clear();
  701. }
  702. void VDirectoryTree::pasteDirectories(VDirectory *p_destDir,
  703. const QVector<QString> &p_dirs,
  704. bool p_isCut)
  705. {
  706. if (!p_destDir || p_dirs.isEmpty()) {
  707. return;
  708. }
  709. int nrPasted = 0;
  710. for (int i = 0; i < p_dirs.size(); ++i) {
  711. VDirectory *dir = g_vnote->getInternalDirectory(p_dirs[i]);
  712. if (!dir) {
  713. qWarning() << "Copied dir is not an internal folder" << p_dirs[i];
  714. VUtils::showMessage(QMessageBox::Warning,
  715. tr("Warning"),
  716. tr("Fail to paste folder <span style=\"%1\">%2</span>.")
  717. .arg(g_config->c_dataTextStyle)
  718. .arg(p_dirs[i]),
  719. tr("VNote could not find this folder in any notebook."),
  720. QMessageBox::Ok,
  721. QMessageBox::Ok,
  722. this);
  723. continue;
  724. }
  725. if (dir == p_destDir) {
  726. continue;
  727. }
  728. QString dirName = dir->getName();
  729. VDirectory *paDir = dir->getParentDirectory();
  730. if (paDir == p_destDir) {
  731. if (p_isCut) {
  732. continue;
  733. }
  734. // Copy and paste in the same folder.
  735. // Rename it to xxx_copy.
  736. dirName = VUtils::generateCopiedDirName(paDir->fetchPath(), dirName);
  737. } else {
  738. // Rename it to xxx_copy if needed.
  739. dirName = VUtils::generateCopiedDirName(p_destDir->fetchPath(), dirName);
  740. }
  741. QString msg;
  742. VDirectory *destDir = NULL;
  743. bool ret = VDirectory::copyDirectory(p_destDir,
  744. dirName,
  745. dir,
  746. p_isCut,
  747. &destDir,
  748. &msg);
  749. if (!ret) {
  750. VUtils::showMessage(QMessageBox::Warning,
  751. tr("Warning"),
  752. tr("Fail to copy folder <span style=\"%1\">%2</span>.")
  753. .arg(g_config->c_dataTextStyle)
  754. .arg(p_dirs[i]),
  755. msg,
  756. QMessageBox::Ok,
  757. QMessageBox::Ok,
  758. this);
  759. }
  760. if (destDir) {
  761. ++nrPasted;
  762. // Update QTreeWidget.
  763. bool isWidget;
  764. QTreeWidgetItem *destItem = findVDirectory(p_destDir, &isWidget);
  765. if (destItem || isWidget) {
  766. updateItemDirectChildren(destItem);
  767. }
  768. if (p_isCut) {
  769. QTreeWidgetItem *srcItem = findVDirectory(paDir, &isWidget);
  770. if (srcItem || isWidget) {
  771. updateItemDirectChildren(srcItem);
  772. }
  773. }
  774. // Broadcast this update
  775. emit directoryUpdated(destDir, p_isCut ? UpdateAction::Moved : UpdateAction::InfoChanged);
  776. }
  777. }
  778. qDebug() << "pasted" << nrPasted << "directories";
  779. if (nrPasted > 0) {
  780. g_mainWin->showStatusMessage(tr("%1 %2 pasted")
  781. .arg(nrPasted)
  782. .arg(nrPasted > 1 ? tr("folders") : tr("folder")));
  783. }
  784. getNewMagic();
  785. }
  786. bool VDirectoryTree::pasteAvailable() const
  787. {
  788. QJsonObject obj = VUtils::clipboardToJson();
  789. if (obj.isEmpty()) {
  790. return false;
  791. }
  792. if (!obj.contains(ClipboardConfig::c_type)) {
  793. return false;
  794. }
  795. ClipboardOpType type = (ClipboardOpType)obj[ClipboardConfig::c_type].toInt();
  796. if (type != ClipboardOpType::CopyDir) {
  797. return false;
  798. }
  799. if (!obj.contains(ClipboardConfig::c_magic)
  800. || !obj.contains(ClipboardConfig::c_isCut)
  801. || !obj.contains(ClipboardConfig::c_dirs)) {
  802. return false;
  803. }
  804. int magic = obj[ClipboardConfig::c_magic].toInt();
  805. if (!checkMagic(magic)) {
  806. return false;
  807. }
  808. QJsonArray dirs = obj[ClipboardConfig::c_dirs].toArray();
  809. return !dirs.isEmpty();
  810. }
  811. void VDirectoryTree::mousePressEvent(QMouseEvent *event)
  812. {
  813. QTreeWidgetItem *item = itemAt(event->pos());
  814. if (!item) {
  815. setCurrentItem(NULL);
  816. }
  817. VTreeWidget::mousePressEvent(event);
  818. }
  819. void VDirectoryTree::keyPressEvent(QKeyEvent *event)
  820. {
  821. int key = event->key();
  822. int modifiers = event->modifiers();
  823. switch (key) {
  824. case Qt::Key_Return:
  825. {
  826. QTreeWidgetItem *item = currentItem();
  827. if (item) {
  828. item->setExpanded(!item->isExpanded());
  829. }
  830. break;
  831. }
  832. case Qt::Key_Asterisk:
  833. {
  834. if (modifiers == Qt::ShiftModifier) {
  835. // *, by default will expand current item recursively.
  836. // We build the tree recursively before the expanding.
  837. QTreeWidgetItem *item = currentItem();
  838. if (item) {
  839. buildSubTree(item, -1);
  840. }
  841. }
  842. break;
  843. }
  844. default:
  845. break;
  846. }
  847. VTreeWidget::keyPressEvent(event);
  848. }
  849. QTreeWidgetItem *VDirectoryTree::findVDirectory(const VDirectory *p_dir, bool *p_widget)
  850. {
  851. if (p_widget) {
  852. *p_widget = false;
  853. }
  854. if (!p_dir) {
  855. return NULL;
  856. } else if (p_dir->getNotebookName() != m_notebook->getName()) {
  857. return NULL;
  858. } else if (p_dir == m_notebook->getRootDir()) {
  859. if (p_widget) {
  860. *p_widget = true;
  861. }
  862. return NULL;
  863. }
  864. bool isWidget;
  865. QTreeWidgetItem *pItem = findVDirectory(p_dir->getParentDirectory(), &isWidget);
  866. if (pItem) {
  867. // Iterate all its children to find the match.
  868. int nrChild = pItem->childCount();
  869. for (int i = 0; i < nrChild; ++i) {
  870. QTreeWidgetItem *item = pItem->child(i);
  871. if (getVDirectory(item) == p_dir) {
  872. return item;
  873. }
  874. }
  875. } else if (isWidget) {
  876. // Iterate all the top-level items.
  877. int nrChild = topLevelItemCount();
  878. for (int i = 0; i < nrChild; ++i) {
  879. QTreeWidgetItem *item = topLevelItem(i);
  880. if (getVDirectory(item) == p_dir) {
  881. return item;
  882. }
  883. }
  884. }
  885. return NULL;
  886. }
  887. bool VDirectoryTree::locateDirectory(const VDirectory *p_directory)
  888. {
  889. if (p_directory) {
  890. if (p_directory->getNotebook() != m_notebook) {
  891. return false;
  892. }
  893. QTreeWidgetItem *item = expandToVDirectory(p_directory);
  894. if (item) {
  895. setCurrentItem(item);
  896. }
  897. return item;
  898. }
  899. return false;
  900. }
  901. QTreeWidgetItem *VDirectoryTree::expandToVDirectory(const VDirectory *p_directory)
  902. {
  903. if (!p_directory
  904. || p_directory->getNotebook() != m_notebook
  905. || p_directory == m_notebook->getRootDir()) {
  906. return NULL;
  907. }
  908. if (p_directory->getParentDirectory() == m_notebook->getRootDir()) {
  909. // Top-level items.
  910. int nrChild = topLevelItemCount();
  911. for (int i = 0; i < nrChild; ++i) {
  912. QTreeWidgetItem *item = topLevelItem(i);
  913. if (getVDirectory(item) == p_directory) {
  914. return item;
  915. }
  916. }
  917. } else {
  918. QTreeWidgetItem *pItem = expandToVDirectory(p_directory->getParentDirectory());
  919. if (!pItem) {
  920. return NULL;
  921. }
  922. int nrChild = pItem->childCount();
  923. if (nrChild == 0) {
  924. buildSubTree(pItem, 1);
  925. }
  926. nrChild = pItem->childCount();
  927. for (int i = 0; i < nrChild; ++i) {
  928. QTreeWidgetItem *item = pItem->child(i);
  929. if (getVDirectory(item) == p_directory) {
  930. return item;
  931. }
  932. }
  933. }
  934. return NULL;
  935. }
  936. void VDirectoryTree::expandSubTree(QTreeWidgetItem *p_item)
  937. {
  938. if (!p_item) {
  939. return;
  940. }
  941. VDirectory *dir = getVDirectory(p_item);
  942. int nrChild = p_item->childCount();
  943. for (int i = 0; i < nrChild; ++i) {
  944. expandSubTree(p_item->child(i));
  945. }
  946. if (dir->isExpanded()) {
  947. Q_ASSERT(nrChild > 0);
  948. expandItem(p_item);
  949. }
  950. }
  951. void VDirectoryTree::showNavigation()
  952. {
  953. VNavigationMode::showNavigation(this);
  954. }
  955. bool VDirectoryTree::handleKeyNavigation(int p_key, bool &p_succeed)
  956. {
  957. return VNavigationMode::handleKeyNavigation(this,
  958. p_key,
  959. p_succeed);
  960. }
  961. int VDirectoryTree::getNewMagic()
  962. {
  963. m_magicForClipboard = (int)QDateTime::currentDateTime().toTime_t();
  964. m_magicForClipboard |= qrand();
  965. return m_magicForClipboard;
  966. }
  967. bool VDirectoryTree::checkMagic(int p_magic) const
  968. {
  969. return m_magicForClipboard == p_magic;
  970. }
  971. void VDirectoryTree::sortItems()
  972. {
  973. if (!m_notebook) {
  974. return;
  975. }
  976. QTreeWidgetItem *item = currentItem();
  977. if (item && item->parent()) {
  978. sortItems(getVDirectory(item->parent()));
  979. } else {
  980. sortItems(m_notebook->getRootDir());
  981. }
  982. if (item) {
  983. setCurrentItem(item);
  984. }
  985. }
  986. void VDirectoryTree::sortItems(VDirectory *p_dir)
  987. {
  988. if (!p_dir) {
  989. return;
  990. }
  991. const QVector<VDirectory *> &dirs = p_dir->getSubDirs();
  992. if (dirs.size() < 2) {
  993. return;
  994. }
  995. bool isNotebook = p_dir->parent() == NULL;
  996. VSortDialog dialog(tr("Sort Folders"),
  997. tr("Sort folders in %1 <span style=\"%2\">%3</span> "
  998. "in the configuration file.")
  999. .arg(isNotebook ? tr("notebook") : tr("folder"))
  1000. .arg(g_config->c_dataTextStyle)
  1001. .arg(isNotebook ? p_dir->getNotebook()->getName() : p_dir->getName()),
  1002. this);
  1003. QTreeWidget *tree = dialog.getTreeWidget();
  1004. tree->clear();
  1005. tree->setColumnCount(2);
  1006. QStringList headers;
  1007. headers << tr("Name") << tr("Created Time");
  1008. tree->setHeaderLabels(headers);
  1009. for (int i = 0; i < dirs.size(); ++i) {
  1010. const VDirectory *dir = dirs[i];
  1011. Q_ASSERT(dir->isOpened());
  1012. QString createdTime = VUtils::displayDateTime(dir->getCreatedTimeUtc().toLocalTime(), true);
  1013. QStringList cols;
  1014. cols << dir->getName() << createdTime;
  1015. QTreeWidgetItem *item = new QTreeWidgetItem(tree, cols);
  1016. item->setData(0, Qt::UserRole, i);
  1017. }
  1018. dialog.treeUpdated();
  1019. if (dialog.exec()) {
  1020. QVector<QVariant> data = dialog.getSortedData();
  1021. Q_ASSERT(data.size() == dirs.size());
  1022. QVector<int> sortedIdx(data.size(), -1);
  1023. for (int i = 0; i < data.size(); ++i) {
  1024. sortedIdx[i] = data[i].toInt();
  1025. }
  1026. qDebug() << "sort dirs" << sortedIdx;
  1027. if (!p_dir->sortSubDirectories(sortedIdx)) {
  1028. VUtils::showMessage(QMessageBox::Warning,
  1029. tr("Warning"),
  1030. tr("Fail to sort folders in %1 <span style=\"%2\">%3</span>.")
  1031. .arg(isNotebook ? tr("notebook") : tr("folder"))
  1032. .arg(g_config->c_dataTextStyle)
  1033. .arg(isNotebook ? p_dir->getNotebook()->getName() : p_dir->getName()),
  1034. "",
  1035. QMessageBox::Ok,
  1036. QMessageBox::Ok,
  1037. this);
  1038. }
  1039. updateItemDirectChildren(findVDirectory(p_dir));
  1040. }
  1041. }
  1042. VDirectory *VDirectoryTree::currentDirectory() const
  1043. {
  1044. QTreeWidgetItem *item = currentItem();
  1045. if (item) {
  1046. return getVDirectory(item);
  1047. }
  1048. return NULL;
  1049. }
  1050. void VDirectoryTree::pinDirectoryToHistory()
  1051. {
  1052. QTreeWidgetItem *curItem = currentItem();
  1053. V_ASSERT(curItem);
  1054. g_mainWin->getHistoryList()->pinFolder(getVDirectory(curItem)->fetchPath());
  1055. g_mainWin->showStatusMessage(tr("1 folder pinned to History"));
  1056. }
  1057. Qt::DropActions VDirectoryTree::supportedDropActions() const
  1058. {
  1059. return Qt::CopyAction | Qt::MoveAction;
  1060. }
  1061. bool VDirectoryTree::dropMimeData(QTreeWidgetItem *p_parent,
  1062. int p_index,
  1063. const QMimeData *p_data,
  1064. Qt::DropAction p_action)
  1065. {
  1066. Q_UNUSED(p_index);
  1067. if (!p_parent) {
  1068. VUtils::showMessage(QMessageBox::Warning,
  1069. tr("Warning"),
  1070. tr("Please drop it on a folder item."),
  1071. "",
  1072. QMessageBox::Ok,
  1073. QMessageBox::Ok,
  1074. this);
  1075. return false;
  1076. }
  1077. if (p_data->hasFormat(ClipboardConfig::c_format)) {
  1078. VDirectory *dir = getVDirectory(p_parent);
  1079. if (!dir) {
  1080. return false;
  1081. }
  1082. QByteArray ba = p_data->data(ClipboardConfig::c_format);
  1083. QJsonObject obj = QJsonDocument::fromJson(ba).object();
  1084. if (obj.isEmpty()) {
  1085. return false;
  1086. }
  1087. if (obj[ClipboardConfig::c_type] != (int)ClipboardOpType::CopyFile) {
  1088. return false;
  1089. }
  1090. QJsonArray files = obj[ClipboardConfig::c_files].toArray();
  1091. if (files.isEmpty()) {
  1092. return false;
  1093. }
  1094. QVector<QString> filesToPaste;
  1095. for (auto const & file : files) {
  1096. filesToPaste.append(file.toString());
  1097. }
  1098. qDebug() << "paste files from dropped mime data" << dir->getName() << filesToPaste;
  1099. g_mainWin->getFileList()->pasteFiles(dir, filesToPaste, p_action == Qt::MoveAction);
  1100. return true;
  1101. }
  1102. return false;
  1103. }
  1104. void VDirectoryTree::dropEvent(QDropEvent *p_event)
  1105. {
  1106. // Distinguish copy and cut.
  1107. int modifiers = p_event->keyboardModifiers();
  1108. if (modifiers & Qt::ControlModifier) {
  1109. p_event->setDropAction(Qt::CopyAction);
  1110. } else {
  1111. // Cut.
  1112. // Will pass to dropMimeData().
  1113. p_event->setDropAction(Qt::MoveAction);
  1114. }
  1115. QTreeWidget::dropEvent(p_event);
  1116. }
  1117. QStringList VDirectoryTree::mimeTypes() const
  1118. {
  1119. return QStringList(ClipboardConfig::c_format);
  1120. }