encodeconvert.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728
  1. #include "encodeconvert.h"
  2. #include "rcglobal.h"
  3. #include "CmpareMode.h"
  4. #include "doctypelistview.h"
  5. #include <QFileDialog>
  6. #include <QTreeWidgetItem>
  7. #include <QDateTime>
  8. #include <QFutureWatcher>
  9. #include <QString>
  10. #include <QtConcurrent>
  11. #include <QInputDialog>
  12. #include <QDragEnterEvent>
  13. #include <QTextCodec>
  14. const int ITEM_CODE = Qt::UserRole + 1;
  15. static QString fileSuffix(const QString& filePath)
  16. {
  17. QFileInfo fi(filePath);
  18. return fi.suffix();
  19. }
  20. static QString getFileSizeFormat(qint64 size)
  21. {
  22. #if 0
  23. if (size <= 1000)
  24. {
  25. return QString("%1").arg(size);
  26. }
  27. QString fileSize = QString("%1").arg(size);
  28. return QString("%1,%2").arg(fileSize.left(fileSize.count() - 3)).arg(fileSize.right(3));
  29. #endif
  30. return QString::number(size);
  31. }
  32. EncodeConvert::EncodeConvert(QWidget *parent): QWidget(parent), m_commitCmpFileNums(0), m_finishCmpFileNums(0), m_menu(nullptr)
  33. {
  34. ui.setupUi(this);
  35. m_extComBoxNum = 0;
  36. connect(ui.treeWidget, &QTreeWidget::itemPressed, this, &EncodeConvert::slot_itemClicked);
  37. setAcceptDrops(true);
  38. }
  39. EncodeConvert::~EncodeConvert()
  40. {
  41. for (auto var : m_supportFileExt)
  42. {
  43. delete var;
  44. }
  45. m_supportFileExt.clear();
  46. }
  47. bool EncodeConvert::isSupportExt(int index, QString ext)
  48. {
  49. bool ret = false;
  50. if (0 == index)
  51. {
  52. ret = DocTypeListView::isSupportExt(ext);
  53. }
  54. else if (index >= 1)
  55. {
  56. int i = index - 1;
  57. if (i < m_supportFileExt.count())
  58. {
  59. ret = m_supportFileExt[i]->contains(ext);
  60. }
  61. }
  62. return ret;
  63. }
  64. //右键菜单
  65. void EncodeConvert::slot_itemClicked(QTreeWidgetItem* item, int /*column*/)
  66. {
  67. if ((item != nullptr) && (Qt::RightButton == QGuiApplication::mouseButtons()))
  68. {
  69. if (m_menu == nullptr)
  70. {
  71. m_menu = new QMenu(this);
  72. m_menu->addAction(tr("&Show File in Explorer..."), this, [&]() {
  73. QString path, cmd;
  74. QTreeWidgetItem* it = ui.treeWidget->currentItem();
  75. if (it == nullptr)
  76. {
  77. return;
  78. }
  79. path = QString("%1").arg(it->data(0, Qt::ToolTipRole).toString());
  80. showFileInExplorer(path);
  81. });
  82. }
  83. m_menu->move(QCursor::pos());
  84. m_menu->show();
  85. }
  86. }
  87. //用户自定义类型
  88. void EncodeConvert::slot_userDefineExt()
  89. {
  90. bool ok = false;
  91. QString text = QInputDialog::getText(this, tr("input file ext()"),tr("ext (Split With :)"), QLineEdit::Normal, QString(".h:.cpp"), &ok);
  92. if (ok && !text.isEmpty())
  93. {
  94. text = text.trimmed();
  95. ui.extComboBox->addItem(text);
  96. QStringList extList = text.split(":");
  97. QMap<QString, bool>* p = new QMap<QString, bool>;
  98. for (QString var : extList)
  99. {
  100. if (var.startsWith("."))
  101. {
  102. p->insert(var.mid(1), true);
  103. }
  104. }
  105. m_supportFileExt.append(p);
  106. ++m_extComBoxNum;
  107. ui.extComboBox->setCurrentIndex(m_extComBoxNum);
  108. }
  109. }
  110. //打开文件目录
  111. void EncodeConvert::slot_selectFile()
  112. {
  113. //加载左边的文件树
  114. QString rootpath = QFileDialog::getExistingDirectory(this, tr("Open Directory"), QString(), QFileDialog::DontResolveSymlinks);
  115. if (!rootpath.isEmpty())
  116. {
  117. ui.treeWidget->clear();
  118. m_fileAttris.clear();
  119. loadDir(rootpath);
  120. setItemIntervalBackground();
  121. scanFileCode();
  122. }
  123. }
  124. int EncodeConvert::allfile(QTreeWidgetItem* root_, QString path_)
  125. {
  126. QList<WalkFileInfo> dirsList;
  127. WalkFileInfo oneDir(0, root_, path_);
  128. dirsList.append(oneDir);
  129. int fileNums = 0;
  130. m_fileDirPath = path_;
  131. while (!dirsList.isEmpty())
  132. {
  133. WalkFileInfo curDir = dirsList.first();
  134. dirsList.pop_front();
  135. QTreeWidgetItem* root = curDir.root;
  136. QString path = curDir.path;
  137. int direction = curDir.direction;
  138. /*添加path路径文件*/
  139. QDir dir(path); //遍历各级子目录
  140. //先获取文件到列表
  141. //再获取文件夹到列表
  142. QFileInfoList folder_list = dir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot); //获取当前所有目录
  143. for (int i = 0; i != folder_list.size(); ++i) //自动递归添加各目录到上一级目录
  144. {
  145. QString namepath = folder_list.at(i).absoluteFilePath(); //获取路径
  146. QFileInfo folderinfo = folder_list.at(i);
  147. QString name = folderinfo.fileName(); //获取目录名
  148. QTreeWidgetItem* childroot = new QTreeWidgetItem(QStringList() << name);
  149. childroot->setIcon(0, QIcon(":/Resources/img/dir.png"));
  150. root->addChild(childroot); //将当前目录添加成path的子项
  151. fileAttriNode node;
  152. node.type = RC_DIR;//是目录
  153. node.selfItem = childroot;
  154. node.parent = root;
  155. node.relativePath = folderinfo.absoluteFilePath();
  156. //把路径名称保存到tips中,后续需要这个来排序,下同
  157. childroot->setData(0, Qt::ToolTipRole, node.relativePath);
  158. m_fileAttris.append(node);
  159. WalkFileInfo oneDir(direction, childroot, namepath);
  160. dirsList.push_front(oneDir);
  161. }
  162. QDir dir_file(path);
  163. dir_file.setFilter(QDir::Files | QDir::NoDotAndDotDot | QDir::NoSymLinks);//获取当前所有文件
  164. QFileInfoList list_file = dir_file.entryInfoList();
  165. for (int i = 0; i < list_file.size(); ++i)
  166. { //将当前目录中所有文件添加到treewidget中
  167. QFileInfo fileInfo = list_file.at(i);
  168. QString name2 = fileInfo.fileName();
  169. QTreeWidgetItem* child = new QTreeWidgetItem(QStringList() << name2);
  170. child->setIcon(0, QIcon(":/Resources/img/point.png"));
  171. child->setText(1, getFileSizeFormat(fileInfo.size()));
  172. /*QString lastModifyTime = fileInfo.lastModified().toString("yy/MM/dd hh:mm:ss");
  173. child->setText(2, lastModifyTime);*/
  174. root->addChild(child);
  175. fileAttriNode node;
  176. node.type = RC_FILE;//是文件
  177. node.selfItem = child;
  178. node.parent = root;
  179. node.relativePath = fileInfo.absoluteFilePath();
  180. //把路径名称保存到tips中,后续需要这个来排序,下同
  181. child->setData(0, Qt::ToolTipRole, node.relativePath);
  182. m_fileAttris.append(node);
  183. }
  184. fileNums += list_file.size();
  185. }
  186. return fileNums;
  187. }
  188. int EncodeConvert::loadDir(QString rootDirPath)
  189. {
  190. QString rootpath = rootDirPath;
  191. QTreeWidgetItem* root = nullptr;
  192. int fileNums = 0;
  193. ui.treeWidget->setColumnWidth(0, 400);
  194. ui.treeWidget->clear();
  195. root = new QTreeWidgetItem(ui.treeWidget);
  196. root->setText(0, rootpath);
  197. root->setExpanded(true);
  198. //第一个节点是目录根节点
  199. fileAttriNode node;
  200. node.type = RC_DIR;//是目录
  201. node.selfItem = root;
  202. node.parent = nullptr;
  203. node.relativePath = ".";
  204. m_fileAttris.append(node);
  205. fileNums = allfile(root, rootpath);
  206. return fileNums;
  207. }
  208. QFuture<EncodeThreadParameter*> EncodeConvert::commitTask(std::function<EncodeThreadParameter* (EncodeThreadParameter*)> fun, EncodeThreadParameter* parameter)
  209. {
  210. /* 这里最开始准备使用信号提交多线程,但是发现std:;function无法使用槽函数机制,需要自己是实现元对象
  211. * 直接使用QtConcurrent::run机制,不仅简单许多,而且在网上看了资料
  212. */
  213. return QtConcurrent::run(fun, parameter);
  214. }
  215. //对比左右文件的大小,sha1值来判断文件是否相等
  216. QFuture<EncodeThreadParameter_*> EncodeConvert::checkFileCode(QString filePath, QTreeWidgetItem* item)
  217. {
  218. EncodeThreadParameter_* p = new EncodeThreadParameter_(filePath);
  219. p->item = item;
  220. //int 0相等 1 不等
  221. return commitTask([](EncodeThreadParameter_* parameter)->EncodeThreadParameter_*
  222. {
  223. parameter->code = CmpareMode::scanFileRealCode(parameter->filepath);
  224. return parameter;
  225. }
  226. , p);
  227. }
  228. CODE_ID EncodeConvert::convertFileToCode(QString& filePath, CODE_ID srcCode, CODE_ID dstCode)
  229. {
  230. if (srcCode == CODE_ID::UNKOWN)
  231. {
  232. return CODE_ID::UNKOWN;
  233. }
  234. QFile file(filePath);
  235. if (!file.open(QIODevice::ReadOnly | QIODevice::ExistingOnly))
  236. {
  237. return CODE_ID::UNKOWN;
  238. }
  239. QByteArray content = file.readAll();
  240. file.close();
  241. int skip = 0;
  242. switch (srcCode)
  243. {
  244. case UNKOWN:
  245. break;
  246. case ANSI:
  247. break;
  248. case UNICODE_LE:
  249. skip = 2;
  250. break;
  251. case UNICODE_BE:
  252. skip = 2;
  253. break;
  254. case UTF8_NOBOM:
  255. break;
  256. case UTF8_BOM:
  257. skip = 3;
  258. break;
  259. case GBK:
  260. break;
  261. default:
  262. break;
  263. }
  264. if (!file.open(QIODevice::WriteOnly | QIODevice::ExistingOnly | QIODevice::Truncate))
  265. {
  266. return CODE_ID::UNKOWN;
  267. }
  268. QByteArray text2Save;
  269. if (skip == 2 && content.size() >= 2)
  270. {
  271. text2Save = QByteArray(content.mid(2));
  272. }
  273. else if (skip == 3 && content.size() >= 3)
  274. {
  275. text2Save = QByteArray(content.mid(3));
  276. }
  277. else
  278. {
  279. text2Save = QByteArray(content);
  280. }
  281. QString textOut;
  282. Encode::tranStrToUNICODE(srcCode, text2Save.data(), text2Save.size(), textOut);
  283. if (dstCode != UNKOWN)
  284. {
  285. //QByteArray codeFlag = Encode::getEncodeStartFlagByte(dstCode);
  286. //20210822 发现大坑,转换到一定格式后,字符串前面自动带了标识,不需要再来检查一次
  287. //if (!codeFlag.isEmpty())
  288. //{
  289. // //先写入标识头
  290. // file.write(codeFlag);
  291. //}
  292. //如果编码是已知如下类型,则后续保存其它行时,不修改编码格式,继续按照原编码进行保存
  293. //前面已经设置过编码了,这里不需要再设置
  294. if (dstCode == CODE_ID::UTF8_BOM)
  295. {
  296. //自动转换不会带UTF-8 BOM,所以自己要在前面写个BOM头。这是一个例外。需要手动写入头
  297. //其他必然BL LE则不需要。
  298. QByteArray codeFlag = Encode::getEncodeStartFlagByte(dstCode);
  299. if (!codeFlag.isEmpty())
  300. {
  301. //先写入标识头
  302. file.write(codeFlag);
  303. }
  304. }
  305. if (textOut.length() > 0)
  306. {
  307. //保存时注意编码问题。这个tolocal已经带了字符BOM头了。只要UTF8_BOM不会带
  308. QByteArray t = textOut.toLocal8Bit();
  309. file.write(textOut.toLocal8Bit());
  310. }
  311. }
  312. file.close();
  313. return dstCode;
  314. }
  315. CODE_ID EncodeConvert::getComboBoxCode(int index){
  316. CODE_ID ret = CODE_ID::UNKOWN;
  317. if (index < CODE_END)
  318. {
  319. ret = (CODE_ID)index;
  320. }
  321. return ret;
  322. };
  323. QFuture<EncodeThreadParameter_*> EncodeConvert::convertFileCode(QString filePath, QTreeWidgetItem* item)
  324. {
  325. EncodeThreadParameter_* p = new EncodeThreadParameter_(filePath);
  326. p->item = item;
  327. CODE_ID srcCode = static_cast<CODE_ID>(item->data(0, ITEM_CODE).toInt());
  328. CODE_ID dstCode = getComboBoxCode(ui.codeToComboBox->currentIndex());
  329. //int 0相等 1 不等
  330. return commitTask([=](EncodeThreadParameter_* parameter)->EncodeThreadParameter_*
  331. {
  332. if (dstCode != CODE_ID::UNKOWN)
  333. {
  334. parameter->code = convertFileToCode(parameter->filepath, srcCode, dstCode);
  335. }
  336. else
  337. {
  338. parameter->code = UNKOWN;
  339. }
  340. return parameter;
  341. }
  342. , p);
  343. }
  344. //20220114 仅仅使用第一行失败编码还是不行,因为utf8和gbk其实有相同的编码范围。
  345. //如果识别第一行为gbk的,则直接使用gbk。但是如果识别为utf8的,则需要识别更多的文本内容,这样会更慢
  346. void EncodeConvert::scanFileCode()
  347. {
  348. m_finishCmpFileNums = 0;
  349. m_commitCmpFileNums = 0;
  350. ui.selectFileBt->setEnabled(false);
  351. ui.startBt->setEnabled(false);
  352. ui.closeBt->setEnabled(false);
  353. ui.logTextBrowser->clear();
  354. ui.logTextBrowser->append(tr("start scan file text code, please wait..."));
  355. for (QList<fileAttriNode>::iterator iter = m_fileAttris.begin(); iter != m_fileAttris.end(); ++iter)
  356. {
  357. if (iter->type == RC_DIR)
  358. {
  359. iter->selfItem->setText(2, QString("--"));
  360. }
  361. else if ((iter->type == RC_FILE) && DocTypeListView::isSupportExt(fileSuffix(iter->relativePath)))
  362. {
  363. QFutureWatcher<EncodeThreadParameter_*>* futureWatcher = new QFutureWatcher<EncodeThreadParameter_*>();
  364. QObject::connect(futureWatcher, &QFutureWatcher<EncodeThreadParameter_>::finished, this, &EncodeConvert::slot_scanFileCode);
  365. futureWatcher->setFuture(this->checkFileCode(iter->relativePath,iter->selfItem));
  366. ++m_commitCmpFileNums;
  367. }
  368. else
  369. {
  370. iter->selfItem->setText(2, tr("ignore"));
  371. }
  372. }
  373. int finishProcessRatio = 0;
  374. while (m_finishCmpFileNums < m_commitCmpFileNums)
  375. {
  376. int curProcessRatio = m_finishCmpFileNums * 100 / m_commitCmpFileNums;
  377. //没%5更新一下
  378. if (curProcessRatio - finishProcessRatio >= 5)
  379. {
  380. finishProcessRatio = curProcessRatio;
  381. ui.logTextBrowser->append(tr("please wait, total file %1,cur scan index %2, scan finish %3%").arg(m_commitCmpFileNums).arg(m_finishCmpFileNums).arg(curProcessRatio));
  382. }
  383. QCoreApplication::processEvents();
  384. }
  385. ui.logTextBrowser->append(tr("scan finished, total file %1").arg(m_commitCmpFileNums));
  386. ui.selectFileBt->setEnabled(true);
  387. ui.startBt->setEnabled(true);
  388. ui.closeBt->setEnabled(true);
  389. }
  390. //文件对比完毕,显示出文件是否意义,不一样则红色字符标识
  391. void EncodeConvert::slot_scanFileCode()
  392. {
  393. QFutureWatcher<EncodeThreadParameter_*>* s = dynamic_cast<QFutureWatcher<EncodeThreadParameter_*> *>(sender());
  394. EncodeThreadParameter_* result = s->result();
  395. //这里释放的内容,其实是在mode里面new出来的
  396. if (result != nullptr)
  397. {
  398. result->item->setText(2, Encode::getCodeNameById(result->code));
  399. result->item->setData(0, ITEM_CODE, result->code);
  400. delete result;
  401. result = nullptr;
  402. }
  403. delete s;
  404. s = nullptr;
  405. ++m_finishCmpFileNums;
  406. }
  407. void EncodeConvert::slot_startConvert()
  408. {
  409. int extComboBoxIndex = ui.extComboBox->currentIndex();
  410. CODE_ID dstCode = getComboBoxCode(ui.codeToComboBox->currentIndex());
  411. m_finishCmpFileNums = 0;
  412. m_commitCmpFileNums = 0;
  413. ui.logTextBrowser->clear();
  414. //如果编码是已知如下类型,则后续保存其它行时,不修改编码格式,继续按照原编码进行保存
  415. QString destCodeName = Encode::getQtCodecNameById(dstCode);
  416. if (destCodeName.isEmpty() || destCodeName == "unknown")
  417. {
  418. //这里永远不会走。因为界面上不会有未知选项
  419. assert(false);
  420. return;
  421. }
  422. else
  423. {
  424. QTextCodec::setCodecForLocale(QTextCodec::codecForName(destCodeName.toStdString().c_str()));
  425. }
  426. ui.selectFileBt->setEnabled(false);
  427. ui.codeToComboBox->setEditable(false);
  428. ui.closeBt->setEnabled(false);
  429. for (QList<fileAttriNode>::iterator iter = m_fileAttris.begin(); iter != m_fileAttris.end(); ++iter)
  430. {
  431. if ((iter->type == RC_FILE) && isSupportExt(extComboBoxIndex, fileSuffix(iter->relativePath)))
  432. {
  433. qDebug() << iter->relativePath;
  434. CODE_ID srcCode = static_cast<CODE_ID>(iter->selfItem->data(0, ITEM_CODE).toInt());
  435. CODE_ID dstCode = getComboBoxCode(ui.codeToComboBox->currentIndex());
  436. if (srcCode != dstCode)
  437. {
  438. QFutureWatcher<EncodeThreadParameter_*>* futureWatcher = new QFutureWatcher<EncodeThreadParameter_*>();
  439. QObject::connect(futureWatcher, &QFutureWatcher<EncodeThreadParameter_>::finished, this, &EncodeConvert::slot_convertFileFinish);
  440. futureWatcher->setFuture(this->convertFileCode(iter->relativePath, iter->selfItem));
  441. ++m_commitCmpFileNums;
  442. }
  443. else
  444. {
  445. iter->selfItem->setText(4, tr("already %1 ignore").arg(Encode::getCodeNameById(srcCode)));
  446. }
  447. }
  448. else
  449. {
  450. iter->selfItem->setText(4, tr("ignore"));
  451. }
  452. }
  453. int finishProcessRatio = 0;
  454. while (m_finishCmpFileNums < m_commitCmpFileNums)
  455. {
  456. int curProcessRatio = m_finishCmpFileNums * 100 / m_commitCmpFileNums;
  457. //没%5更新一下
  458. if (curProcessRatio - finishProcessRatio >= 5)
  459. {
  460. finishProcessRatio = curProcessRatio;
  461. ui.logTextBrowser->append(tr("total file %1,cur deal index %2,finish %3%").arg(m_commitCmpFileNums).arg(m_finishCmpFileNums).arg(curProcessRatio));
  462. }
  463. QCoreApplication::processEvents();
  464. }
  465. ui.logTextBrowser->append(tr("total file %1,cur deal index %2,finish 100%").arg(m_commitCmpFileNums).arg(m_finishCmpFileNums));
  466. ui.logTextBrowser->append(tr("convert finished !"));
  467. ui.selectFileBt->setEnabled(true);
  468. ui.codeToComboBox->setEditable(true);
  469. ui.closeBt->setEnabled(true);
  470. }
  471. //转换完成,设置当前表格上的显示状态
  472. void EncodeConvert::slot_convertFileFinish()
  473. {
  474. QFutureWatcher<EncodeThreadParameter_*>* s = dynamic_cast<QFutureWatcher<EncodeThreadParameter_*> *>(sender());
  475. EncodeThreadParameter_* result = s->result();
  476. //这里释放的内容,其实是在mode里面new出来的
  477. if (result != nullptr)
  478. {
  479. if (result->code != UNKOWN)
  480. {
  481. result->item->setText(3, Encode::getCodeNameById(result->code));
  482. result->item->setText(4, tr("convert finish"));
  483. }
  484. else
  485. {
  486. result->item->setText(4, tr("convert fail"));
  487. ui.logTextBrowser->append(tr("file %1 convert failed,pleas check...").arg(result->item->data(0, Qt::ToolTipRole).toString()));
  488. }
  489. result->item->setData(0, ITEM_CODE, result->code);
  490. delete result;
  491. result = nullptr;
  492. }
  493. delete s;
  494. s = nullptr;
  495. ++m_finishCmpFileNums;
  496. }
  497. //对item进行间隔着色
  498. void EncodeConvert::setItemIntervalBackground()
  499. {
  500. int curItemIndex = 0;
  501. QTreeWidgetItemIterator it(ui.treeWidget);
  502. while (*it) {
  503. if (curItemIndex % 2 == 1)
  504. {
  505. setItemBackground(*it, QColor(0xf8faf9));
  506. }
  507. ++it;
  508. ++curItemIndex;
  509. }
  510. }
  511. void EncodeConvert::setItemBackground(QTreeWidgetItem* item, const QColor& color)
  512. {
  513. QBrush b(color);
  514. item->setBackground(0, b);
  515. item->setBackground(1, b);
  516. item->setBackground(2, b);
  517. item->setBackground(3, b);
  518. item->setBackground(4, b);
  519. }
  520. void EncodeConvert::dragEnterEvent(QDragEnterEvent* event)
  521. {
  522. if (event->mimeData()->hasFormat("text/uri-list")) //只能打开文本文件
  523. {
  524. event->accept(); //可以在这个窗口部件上拖放对象
  525. }
  526. else
  527. {
  528. event->ignore();
  529. }
  530. }
  531. void EncodeConvert::dropEvent(QDropEvent* e)
  532. {
  533. QList<QUrl> urls = e->mimeData()->urls();
  534. if (urls.isEmpty())
  535. return;
  536. QString dirName = urls.first().toLocalFile();
  537. if (dirName.isEmpty())
  538. {
  539. return;
  540. }
  541. QDir dir(dirName);
  542. if (!dir.exists())
  543. {
  544. ui.logTextBrowser->append(tr("please drop a file dir ..."));
  545. return;
  546. }
  547. ui.treeWidget->clear();
  548. m_fileAttris.clear();
  549. loadDir(dirName);
  550. setItemIntervalBackground();
  551. scanFileCode();
  552. e->accept();
  553. }