vfilelist.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701
  1. #include <QtDebug>
  2. #include <QtWidgets>
  3. #include <QUrl>
  4. #include "vfilelist.h"
  5. #include "vconfigmanager.h"
  6. #include "dialog/vnewfiledialog.h"
  7. #include "dialog/vfileinfodialog.h"
  8. #include "vnote.h"
  9. #include "veditarea.h"
  10. #include "utils/vutils.h"
  11. #include "vfile.h"
  12. #include "vconfigmanager.h"
  13. extern VConfigManager vconfig;
  14. extern VNote *g_vnote;
  15. VFileList::VFileList(QWidget *parent)
  16. : QWidget(parent), VNavigationMode()
  17. {
  18. setupUI();
  19. initActions();
  20. }
  21. void VFileList::setupUI()
  22. {
  23. fileList = new QListWidget(this);
  24. fileList->setContextMenuPolicy(Qt::CustomContextMenu);
  25. fileList->setSelectionMode(QAbstractItemView::ExtendedSelection);
  26. fileList->setDragDropMode(QAbstractItemView::InternalMove);
  27. fileList->setObjectName("FileList");
  28. QVBoxLayout *mainLayout = new QVBoxLayout;
  29. mainLayout->addWidget(fileList);
  30. mainLayout->setContentsMargins(0, 0, 0, 0);
  31. connect(fileList, &QListWidget::customContextMenuRequested,
  32. this, &VFileList::contextMenuRequested);
  33. connect(fileList, &QListWidget::itemClicked,
  34. this, &VFileList::handleItemClicked);
  35. connect(fileList->model(), &QAbstractItemModel::rowsMoved,
  36. this, &VFileList::handleRowsMoved);
  37. setLayout(mainLayout);
  38. }
  39. void VFileList::initActions()
  40. {
  41. newFileAct = new QAction(QIcon(":/resources/icons/create_note.svg"),
  42. tr("&New Note"), this);
  43. newFileAct->setToolTip(tr("Create a note in current folder"));
  44. connect(newFileAct, SIGNAL(triggered(bool)),
  45. this, SLOT(newFile()));
  46. deleteFileAct = new QAction(QIcon(":/resources/icons/delete_note.svg"),
  47. tr("&Delete"), this);
  48. deleteFileAct->setToolTip(tr("Delete selected note"));
  49. connect(deleteFileAct, SIGNAL(triggered(bool)),
  50. this, SLOT(deleteFile()));
  51. fileInfoAct = new QAction(QIcon(":/resources/icons/note_info.svg"),
  52. tr("&Info"), this);
  53. fileInfoAct->setToolTip(tr("View and edit current note's information"));
  54. connect(fileInfoAct, SIGNAL(triggered(bool)),
  55. this, SLOT(fileInfo()));
  56. copyAct = new QAction(QIcon(":/resources/icons/copy.svg"),
  57. tr("&Copy"), this);
  58. copyAct->setToolTip(tr("Copy selected notes"));
  59. connect(copyAct, &QAction::triggered,
  60. this, &VFileList::copySelectedFiles);
  61. cutAct = new QAction(QIcon(":/resources/icons/cut.svg"),
  62. tr("C&ut"), this);
  63. cutAct->setToolTip(tr("Cut selected notes"));
  64. connect(cutAct, &QAction::triggered,
  65. this, &VFileList::cutSelectedFiles);
  66. pasteAct = new QAction(QIcon(":/resources/icons/paste.svg"),
  67. tr("&Paste"), this);
  68. pasteAct->setToolTip(tr("Paste notes in current folder"));
  69. connect(pasteAct, &QAction::triggered,
  70. this, &VFileList::pasteFilesInCurDir);
  71. m_openLocationAct = new QAction(tr("&Open Note Location"), this);
  72. m_openLocationAct->setToolTip(tr("Open the folder containing this note in operating system"));
  73. connect(m_openLocationAct, &QAction::triggered,
  74. this, &VFileList::openFileLocation);
  75. }
  76. void VFileList::setDirectory(VDirectory *p_directory)
  77. {
  78. if (m_directory == p_directory) {
  79. return;
  80. }
  81. m_directory = p_directory;
  82. if (!m_directory) {
  83. fileList->clear();
  84. return;
  85. }
  86. qDebug() << "filelist set folder" << m_directory->getName();
  87. updateFileList();
  88. }
  89. void VFileList::updateFileList()
  90. {
  91. fileList->clear();
  92. if (!m_directory->open()) {
  93. return;
  94. }
  95. const QVector<VFile *> &files = m_directory->getFiles();
  96. for (int i = 0; i < files.size(); ++i) {
  97. VFile *file = files[i];
  98. insertFileListItem(file);
  99. }
  100. }
  101. void VFileList::fileInfo()
  102. {
  103. QListWidgetItem *curItem = fileList->currentItem();
  104. V_ASSERT(curItem);
  105. fileInfo(getVFile(curItem));
  106. }
  107. void VFileList::openFileLocation() const
  108. {
  109. QListWidgetItem *curItem = fileList->currentItem();
  110. V_ASSERT(curItem);
  111. QUrl url = QUrl::fromLocalFile(getVFile(curItem)->retriveBasePath());
  112. QDesktopServices::openUrl(url);
  113. }
  114. void VFileList::fileInfo(VFile *p_file)
  115. {
  116. if (!p_file) {
  117. return;
  118. }
  119. VDirectory *dir = p_file->getDirectory();
  120. QString info;
  121. QString defaultName = p_file->getName();
  122. QString curName = defaultName;
  123. do {
  124. VFileInfoDialog dialog(tr("Note Information"), info, defaultName, this);
  125. if (dialog.exec() == QDialog::Accepted) {
  126. QString name = dialog.getNameInput();
  127. if (name == curName) {
  128. return;
  129. }
  130. if (dir->findFile(name)) {
  131. info = "Name already exists. Please choose another name.";
  132. defaultName = name;
  133. continue;
  134. }
  135. if (!promptForDocTypeChange(p_file, QDir(p_file->retriveBasePath()).filePath(name))) {
  136. return;
  137. }
  138. if (!p_file->rename(name)) {
  139. VUtils::showMessage(QMessageBox::Warning, tr("Warning"),
  140. tr("Fail to rename note <span style=\"%1\">%2</span>.")
  141. .arg(vconfig.c_dataTextStyle).arg(curName), "",
  142. QMessageBox::Ok, QMessageBox::Ok, this);
  143. return;
  144. }
  145. QListWidgetItem *item = findItem(p_file);
  146. if (item) {
  147. fillItem(item, p_file);
  148. }
  149. emit fileUpdated(p_file);
  150. }
  151. break;
  152. } while (true);
  153. }
  154. void VFileList::fillItem(QListWidgetItem *p_item, const VFile *p_file)
  155. {
  156. unsigned long long ptr = (long long)p_file;
  157. p_item->setData(Qt::UserRole, ptr);
  158. p_item->setToolTip(p_file->getName());
  159. p_item->setText(p_file->getName());
  160. V_ASSERT(sizeof(p_file) <= sizeof(ptr));
  161. }
  162. QListWidgetItem* VFileList::insertFileListItem(VFile *file, bool atFront)
  163. {
  164. V_ASSERT(file);
  165. QListWidgetItem *item = new QListWidgetItem();
  166. fillItem(item, file);
  167. if (atFront) {
  168. fileList->insertItem(0, item);
  169. } else {
  170. fileList->addItem(item);
  171. }
  172. // Qt seems not to update the QListWidget correctly. Manually force it to repaint.
  173. fileList->update();
  174. qDebug() << "VFileList adds" << file->getName();
  175. return item;
  176. }
  177. void VFileList::removeFileListItem(QListWidgetItem *item)
  178. {
  179. fileList->setCurrentRow(-1);
  180. fileList->removeItemWidget(item);
  181. delete item;
  182. // Qt seems not to update the QListWidget correctly. Manually force it to repaint.
  183. fileList->update();
  184. }
  185. void VFileList::newFile()
  186. {
  187. if (!m_directory) {
  188. return;
  189. }
  190. QString info = tr("Create a note in <span style=\"%1\">%2</span>.")
  191. .arg(vconfig.c_dataTextStyle).arg(m_directory->getName());
  192. info = info + "<br>" + tr("Note with name ending with \".md\" will be treated as Markdown type.");
  193. QString text(tr("Note &name:"));
  194. QString defaultText("new_note.md");
  195. do {
  196. VNewFileDialog dialog(tr("Create Note"), info, text, defaultText, this);
  197. if (dialog.exec() == QDialog::Accepted) {
  198. QString name = dialog.getNameInput();
  199. if (m_directory->findFile(name)) {
  200. info = tr("Name already exists. Please choose another name.");
  201. defaultText = name;
  202. continue;
  203. }
  204. VFile *file = m_directory->createFile(name);
  205. if (!file) {
  206. VUtils::showMessage(QMessageBox::Warning, tr("Warning"),
  207. tr("Fail to create note <span style=\"%1\">%2</span>.")
  208. .arg(vconfig.c_dataTextStyle).arg(name), "",
  209. QMessageBox::Ok, QMessageBox::Ok, this);
  210. return;
  211. }
  212. QVector<QListWidgetItem *> items = updateFileListAdded();
  213. Q_ASSERT(items.size() == 1);
  214. fileList->setCurrentItem(items[0], QItemSelectionModel::ClearAndSelect);
  215. // Qt seems not to update the QListWidget correctly. Manually force it to repaint.
  216. fileList->update();
  217. // Open it in edit mode
  218. emit fileCreated(file, OpenFileMode::Edit);
  219. }
  220. break;
  221. } while (true);
  222. }
  223. QVector<QListWidgetItem *> VFileList::updateFileListAdded()
  224. {
  225. QVector<QListWidgetItem *> ret;
  226. const QVector<VFile *> &files = m_directory->getFiles();
  227. for (int i = 0; i < files.size(); ++i) {
  228. VFile *file = files[i];
  229. if (i >= fileList->count()) {
  230. QListWidgetItem *item = insertFileListItem(file, false);
  231. ret.append(item);
  232. } else {
  233. VFile *itemFile = getVFile(fileList->item(i));
  234. if (itemFile != file) {
  235. QListWidgetItem *item = insertFileListItem(file, false);
  236. ret.append(item);
  237. }
  238. }
  239. }
  240. qDebug() << ret.size() << "items added";
  241. return ret;
  242. }
  243. // Delete the file related to current item
  244. void VFileList::deleteFile()
  245. {
  246. QList<QListWidgetItem *> items = fileList->selectedItems();
  247. Q_ASSERT(!items.isEmpty());
  248. for (int i = 0; i < items.size(); ++i) {
  249. deleteFile(getVFile(items.at(i)));
  250. }
  251. }
  252. // @p_file may or may not be listed in VFileList
  253. void VFileList::deleteFile(VFile *p_file)
  254. {
  255. if (!p_file) {
  256. return;
  257. }
  258. VDirectory *dir = p_file->getDirectory();
  259. QString fileName = p_file->getName();
  260. int ret = VUtils::showMessage(QMessageBox::Warning, tr("Warning"),
  261. tr("Are you sure to delete note <span style=\"%1\">%2</span>?")
  262. .arg(vconfig.c_dataTextStyle).arg(fileName),
  263. tr("<span style=\"%1\">WARNING</span>: The files (including images) "
  264. "deleted may be UNRECOVERABLE!")
  265. .arg(vconfig.c_warningTextStyle),
  266. QMessageBox::Ok | QMessageBox::Cancel,
  267. QMessageBox::Ok, this, MessageBoxType::Danger);
  268. if (ret == QMessageBox::Ok) {
  269. editArea->closeFile(p_file, true);
  270. // Remove the item before deleting it totally, or p_file will be invalid.
  271. QListWidgetItem *item = findItem(p_file);
  272. if (item) {
  273. removeFileListItem(item);
  274. }
  275. dir->deleteFile(p_file);
  276. }
  277. }
  278. void VFileList::contextMenuRequested(QPoint pos)
  279. {
  280. QListWidgetItem *item = fileList->itemAt(pos);
  281. QMenu menu(this);
  282. menu.setToolTipsVisible(true);
  283. if (!m_directory) {
  284. return;
  285. }
  286. menu.addAction(newFileAct);
  287. if (item) {
  288. menu.addAction(deleteFileAct);
  289. menu.addSeparator();
  290. menu.addAction(copyAct);
  291. menu.addAction(cutAct);
  292. }
  293. if (VUtils::opTypeInClipboard() == ClipboardOpType::CopyFile
  294. && !m_copiedFiles.isEmpty()) {
  295. if (!item) {
  296. menu.addSeparator();
  297. }
  298. menu.addAction(pasteAct);
  299. }
  300. if (item) {
  301. menu.addSeparator();
  302. menu.addAction(m_openLocationAct);
  303. if (fileList->selectedItems().size() == 1) {
  304. menu.addAction(fileInfoAct);
  305. }
  306. }
  307. menu.exec(fileList->mapToGlobal(pos));
  308. }
  309. QListWidgetItem* VFileList::findItem(const VFile *p_file)
  310. {
  311. if (!p_file || p_file->getDirectory() != m_directory) {
  312. return NULL;
  313. }
  314. int nrChild = fileList->count();
  315. for (int i = 0; i < nrChild; ++i) {
  316. QListWidgetItem *item = fileList->item(i);
  317. if (p_file == getVFile(item)) {
  318. return item;
  319. }
  320. }
  321. return NULL;
  322. }
  323. void VFileList::handleItemClicked(QListWidgetItem *currentItem)
  324. {
  325. if (!currentItem) {
  326. emit fileClicked(NULL);
  327. return;
  328. }
  329. // Qt seems not to update the QListWidget correctly. Manually force it to repaint.
  330. fileList->update();
  331. emit fileClicked(getVFile(currentItem), OpenFileMode::Read);
  332. }
  333. bool VFileList::importFile(const QString &p_srcFilePath)
  334. {
  335. if (p_srcFilePath.isEmpty()) {
  336. return false;
  337. }
  338. Q_ASSERT(m_directory);
  339. // Copy file @name to current directory
  340. QString targetPath = m_directory->retrivePath();
  341. QString srcName = VUtils::fileNameFromPath(p_srcFilePath);
  342. if (srcName.isEmpty()) {
  343. return false;
  344. }
  345. QString targetFilePath = QDir(targetPath).filePath(srcName);
  346. bool ret = VUtils::copyFile(p_srcFilePath, targetFilePath, false);
  347. if (!ret) {
  348. return false;
  349. }
  350. VFile *destFile = m_directory->addFile(srcName, -1);
  351. if (destFile) {
  352. return insertFileListItem(destFile, false);
  353. }
  354. return false;
  355. }
  356. void VFileList::copySelectedFiles(bool p_isCut)
  357. {
  358. QList<QListWidgetItem *> items = fileList->selectedItems();
  359. if (items.isEmpty()) {
  360. return;
  361. }
  362. QJsonArray files;
  363. m_copiedFiles.clear();
  364. for (int i = 0; i < items.size(); ++i) {
  365. VFile *file = getVFile(items[i]);
  366. QJsonObject fileJson;
  367. fileJson["notebook"] = file->getNotebookName();
  368. fileJson["path"] = file->retrivePath();
  369. files.append(fileJson);
  370. m_copiedFiles.append(file);
  371. }
  372. copyFileInfoToClipboard(files, p_isCut);
  373. }
  374. void VFileList::cutSelectedFiles()
  375. {
  376. copySelectedFiles(true);
  377. }
  378. void VFileList::copyFileInfoToClipboard(const QJsonArray &p_files, bool p_isCut)
  379. {
  380. QJsonObject clip;
  381. clip["operation"] = (int)ClipboardOpType::CopyFile;
  382. clip["is_cut"] = p_isCut;
  383. clip["sources"] = p_files;
  384. QClipboard *clipboard = QApplication::clipboard();
  385. clipboard->setText(QJsonDocument(clip).toJson(QJsonDocument::Compact));
  386. }
  387. void VFileList::pasteFilesInCurDir()
  388. {
  389. pasteFiles(m_directory);
  390. }
  391. void VFileList::pasteFiles(VDirectory *p_destDir)
  392. {
  393. qDebug() << "paste files to" << p_destDir->getName();
  394. QClipboard *clipboard = QApplication::clipboard();
  395. QString text = clipboard->text();
  396. QJsonObject clip = QJsonDocument::fromJson(text.toLocal8Bit()).object();
  397. Q_ASSERT(!clip.isEmpty() && clip["operation"] == (int)ClipboardOpType::CopyFile);
  398. bool isCut = clip["is_cut"].toBool();
  399. int nrPasted = 0;
  400. for (int i = 0; i < m_copiedFiles.size(); ++i) {
  401. QPointer<VFile> srcFile = m_copiedFiles[i];
  402. if (!srcFile) {
  403. continue;
  404. }
  405. QString fileName = srcFile->getName();
  406. VDirectory *srcDir = srcFile->getDirectory();
  407. if (srcDir == p_destDir && !isCut) {
  408. // Copy and paste in the same directory.
  409. // Rename it to xx_copy.md
  410. fileName = VUtils::generateCopiedFileName(srcDir->retrivePath(), fileName);
  411. }
  412. if (copyFile(p_destDir, fileName, srcFile, isCut)) {
  413. nrPasted++;
  414. } else {
  415. VUtils::showMessage(QMessageBox::Warning, tr("Warning"),
  416. tr("Fail to copy note <span style=\"%1\">%2</span>.")
  417. .arg(vconfig.c_dataTextStyle).arg(srcFile->getName()),
  418. tr("Please check if there already exists a file with the same name in the target folder."),
  419. QMessageBox::Ok, QMessageBox::Ok, this);
  420. }
  421. }
  422. qDebug() << "pasted" << nrPasted << "files sucessfully";
  423. clipboard->clear();
  424. m_copiedFiles.clear();
  425. }
  426. bool VFileList::copyFile(VDirectory *p_destDir, const QString &p_destName, VFile *p_file, bool p_cut)
  427. {
  428. QString srcPath = QDir::cleanPath(p_file->retrivePath());
  429. QString destPath = QDir::cleanPath(QDir(p_destDir->retrivePath()).filePath(p_destName));
  430. if (srcPath == destPath) {
  431. return true;
  432. }
  433. // If change the file type, we need to close it first
  434. if (!promptForDocTypeChange(p_file, destPath)) {
  435. return false;
  436. }
  437. VFile *destFile = VDirectory::copyFile(p_destDir, p_destName, p_file, p_cut);
  438. updateFileList();
  439. if (destFile) {
  440. emit fileUpdated(destFile);
  441. }
  442. return destFile != NULL;
  443. }
  444. bool VFileList::promptForDocTypeChange(const VFile *p_file, const QString &p_newFilePath)
  445. {
  446. DocType docType = p_file->getDocType();
  447. DocType newDocType = VUtils::docTypeFromName(p_newFilePath);
  448. if (docType != newDocType) {
  449. if (editArea->isFileOpened(p_file)) {
  450. int ret = VUtils::showMessage(QMessageBox::Warning, tr("Warning"),
  451. tr("The renaming will change the note type."),
  452. tr("You should close the note <span style=\"%1\">%2</span> before continue.")
  453. .arg(vconfig.c_dataTextStyle).arg(p_file->getName()),
  454. QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Ok, this);
  455. if (QMessageBox::Ok == ret) {
  456. if (!editArea->closeFile(p_file, false)) {
  457. return false;
  458. }
  459. } else {
  460. return false;
  461. }
  462. }
  463. }
  464. return true;
  465. }
  466. void VFileList::keyPressEvent(QKeyEvent *event)
  467. {
  468. int key = event->key();
  469. int modifiers = event->modifiers();
  470. switch (key) {
  471. case Qt::Key_Return:
  472. {
  473. QListWidgetItem *item = fileList->currentItem();
  474. if (item) {
  475. handleItemClicked(item);
  476. }
  477. break;
  478. }
  479. case Qt::Key_J:
  480. {
  481. if (modifiers == Qt::ControlModifier) {
  482. event->accept();
  483. QKeyEvent *downEvent = new QKeyEvent(QEvent::KeyPress, Qt::Key_Down,
  484. Qt::NoModifier);
  485. QCoreApplication::postEvent(fileList, downEvent);
  486. return;
  487. }
  488. break;
  489. }
  490. case Qt::Key_K:
  491. {
  492. if (modifiers == Qt::ControlModifier) {
  493. event->accept();
  494. QKeyEvent *upEvent = new QKeyEvent(QEvent::KeyPress, Qt::Key_Up,
  495. Qt::NoModifier);
  496. QCoreApplication::postEvent(fileList, upEvent);
  497. return;
  498. }
  499. break;
  500. }
  501. default:
  502. break;
  503. }
  504. QWidget::keyPressEvent(event);
  505. }
  506. void VFileList::focusInEvent(QFocusEvent * /* p_event */)
  507. {
  508. fileList->setFocus();
  509. }
  510. bool VFileList::locateFile(const VFile *p_file)
  511. {
  512. if (p_file) {
  513. if (p_file->getDirectory() != m_directory) {
  514. return false;
  515. }
  516. QListWidgetItem *item = findItem(p_file);
  517. if (item) {
  518. fileList->setCurrentItem(item, QItemSelectionModel::ClearAndSelect);
  519. }
  520. }
  521. return false;
  522. }
  523. void VFileList::handleRowsMoved(const QModelIndex &p_parent, int p_start, int p_end, const QModelIndex &p_destination, int p_row)
  524. {
  525. if (p_parent == p_destination) {
  526. // Items[p_start, p_end] are moved to p_row.
  527. m_directory->reorderFiles(p_start, p_end, p_row);
  528. Q_ASSERT(identicalListWithDirectory());
  529. }
  530. }
  531. bool VFileList::identicalListWithDirectory() const
  532. {
  533. const QVector<VFile *> files = m_directory->getFiles();
  534. int nrItems = fileList->count();
  535. if (nrItems != files.size()) {
  536. return false;
  537. }
  538. for (int i = 0; i < nrItems; ++i) {
  539. if (getVFile(fileList->item(i)) != files.at(i)) {
  540. return false;
  541. }
  542. }
  543. return true;
  544. }
  545. void VFileList::registerNavigation(QChar p_majorKey)
  546. {
  547. m_majorKey = p_majorKey;
  548. V_ASSERT(m_keyMap.empty());
  549. V_ASSERT(m_naviLabels.empty());
  550. }
  551. void VFileList::showNavigation()
  552. {
  553. // Clean up.
  554. m_keyMap.clear();
  555. for (auto label : m_naviLabels) {
  556. delete label;
  557. }
  558. m_naviLabels.clear();
  559. if (!isVisible()) {
  560. return;
  561. }
  562. // Generate labels for visible items.
  563. auto items = getVisibleItems();
  564. for (int i = 0; i < 26 && i < items.size(); ++i) {
  565. QChar key('a' + i);
  566. m_keyMap[key] = items[i];
  567. QString str = QString(m_majorKey) + key;
  568. QLabel *label = new QLabel(str, this);
  569. label->setStyleSheet(g_vnote->getNavigationLabelStyle(str));
  570. label->move(fileList->visualItemRect(items[i]).topLeft());
  571. label->show();
  572. m_naviLabels.append(label);
  573. }
  574. }
  575. void VFileList::hideNavigation()
  576. {
  577. m_keyMap.clear();
  578. for (auto label : m_naviLabels) {
  579. delete label;
  580. }
  581. m_naviLabels.clear();
  582. }
  583. bool VFileList::handleKeyNavigation(int p_key, bool &p_succeed)
  584. {
  585. static bool secondKey = false;
  586. bool ret = false;
  587. p_succeed = false;
  588. QChar keyChar = VUtils::keyToChar(p_key);
  589. if (secondKey && !keyChar.isNull()) {
  590. secondKey = false;
  591. p_succeed = true;
  592. ret = true;
  593. auto it = m_keyMap.find(keyChar);
  594. if (it != m_keyMap.end()) {
  595. fileList->setCurrentItem(it.value(), QItemSelectionModel::ClearAndSelect);
  596. fileList->setFocus();
  597. }
  598. } else if (keyChar == m_majorKey) {
  599. // Major key pressed.
  600. // Need second key if m_keyMap is not empty.
  601. if (m_keyMap.isEmpty()) {
  602. p_succeed = true;
  603. } else {
  604. secondKey = true;
  605. }
  606. ret = true;
  607. }
  608. return ret;
  609. }
  610. QList<QListWidgetItem *> VFileList::getVisibleItems() const
  611. {
  612. QList<QListWidgetItem *> items;
  613. for (int i = 0; i < fileList->count(); ++i) {
  614. QListWidgetItem *item = fileList->item(i);
  615. if (!item->isHidden()) {
  616. items.append(item);
  617. }
  618. }
  619. return items;
  620. }