| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728 |
- #include "encodeconvert.h"
- #include "rcglobal.h"
- #include "CmpareMode.h"
- #include "doctypelistview.h"
- #include <QFileDialog>
- #include <QTreeWidgetItem>
- #include <QDateTime>
- #include <QFutureWatcher>
- #include <QString>
- #include <QtConcurrent>
- #include <QInputDialog>
- #include <QDragEnterEvent>
- #include <QTextCodec>
- const int ITEM_CODE = Qt::UserRole + 1;
- static QString fileSuffix(const QString& filePath)
- {
- QFileInfo fi(filePath);
- return fi.suffix();
- }
- static QString getFileSizeFormat(qint64 size)
- {
- #if 0
- if (size <= 1000)
- {
- return QString("%1").arg(size);
- }
- QString fileSize = QString("%1").arg(size);
- return QString("%1,%2").arg(fileSize.left(fileSize.count() - 3)).arg(fileSize.right(3));
- #endif
- return QString::number(size);
- }
- EncodeConvert::EncodeConvert(QWidget *parent): QWidget(parent), m_commitCmpFileNums(0), m_finishCmpFileNums(0), m_menu(nullptr)
- {
- ui.setupUi(this);
- m_extComBoxNum = 0;
- connect(ui.treeWidget, &QTreeWidget::itemPressed, this, &EncodeConvert::slot_itemClicked);
- setAcceptDrops(true);
- }
- EncodeConvert::~EncodeConvert()
- {
- for (auto var : m_supportFileExt)
- {
- delete var;
- }
- m_supportFileExt.clear();
- }
- bool EncodeConvert::isSupportExt(int index, QString ext)
- {
- bool ret = false;
- if (0 == index)
- {
- ret = DocTypeListView::isSupportExt(ext);
- }
- else if (index >= 1)
- {
- int i = index - 1;
- if (i < m_supportFileExt.count())
- {
- ret = m_supportFileExt[i]->contains(ext);
- }
- }
- return ret;
- }
- //右键菜单
- void EncodeConvert::slot_itemClicked(QTreeWidgetItem* item, int /*column*/)
- {
- if ((item != nullptr) && (Qt::RightButton == QGuiApplication::mouseButtons()))
- {
- if (m_menu == nullptr)
- {
- m_menu = new QMenu(this);
- m_menu->addAction(tr("&Show File in Explorer..."), this, [&]() {
- QString path, cmd;
- QTreeWidgetItem* it = ui.treeWidget->currentItem();
- if (it == nullptr)
- {
- return;
- }
- path = QString("%1").arg(it->data(0, Qt::ToolTipRole).toString());
- showFileInExplorer(path);
- });
- }
- m_menu->move(QCursor::pos());
- m_menu->show();
- }
- }
- //用户自定义类型
- void EncodeConvert::slot_userDefineExt()
- {
- bool ok = false;
- QString text = QInputDialog::getText(this, tr("input file ext()"),tr("ext (Split With :)"), QLineEdit::Normal, QString(".h:.cpp"), &ok);
- if (ok && !text.isEmpty())
- {
- text = text.trimmed();
- ui.extComboBox->addItem(text);
- QStringList extList = text.split(":");
- QMap<QString, bool>* p = new QMap<QString, bool>;
- for (QString var : extList)
- {
- if (var.startsWith("."))
- {
- p->insert(var.mid(1), true);
- }
- }
- m_supportFileExt.append(p);
- ++m_extComBoxNum;
- ui.extComboBox->setCurrentIndex(m_extComBoxNum);
- }
- }
- //打开文件目录
- void EncodeConvert::slot_selectFile()
- {
- //加载左边的文件树
- QString rootpath = QFileDialog::getExistingDirectory(this, tr("Open Directory"), QString(), QFileDialog::DontResolveSymlinks);
- if (!rootpath.isEmpty())
- {
- ui.treeWidget->clear();
- m_fileAttris.clear();
- loadDir(rootpath);
- setItemIntervalBackground();
- scanFileCode();
- }
-
- }
- int EncodeConvert::allfile(QTreeWidgetItem* root_, QString path_)
- {
- QList<WalkFileInfo> dirsList;
- WalkFileInfo oneDir(0, root_, path_);
- dirsList.append(oneDir);
- int fileNums = 0;
- m_fileDirPath = path_;
- while (!dirsList.isEmpty())
- {
- WalkFileInfo curDir = dirsList.first();
- dirsList.pop_front();
- QTreeWidgetItem* root = curDir.root;
- QString path = curDir.path;
- int direction = curDir.direction;
- /*添加path路径文件*/
- QDir dir(path); //遍历各级子目录
- //先获取文件到列表
- //再获取文件夹到列表
- QFileInfoList folder_list = dir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot); //获取当前所有目录
- for (int i = 0; i != folder_list.size(); ++i) //自动递归添加各目录到上一级目录
- {
- QString namepath = folder_list.at(i).absoluteFilePath(); //获取路径
- QFileInfo folderinfo = folder_list.at(i);
- QString name = folderinfo.fileName(); //获取目录名
- QTreeWidgetItem* childroot = new QTreeWidgetItem(QStringList() << name);
- childroot->setIcon(0, QIcon(":/Resources/img/dir.png"));
- root->addChild(childroot); //将当前目录添加成path的子项
- fileAttriNode node;
- node.type = RC_DIR;//是目录
- node.selfItem = childroot;
- node.parent = root;
- node.relativePath = folderinfo.absoluteFilePath();
- //把路径名称保存到tips中,后续需要这个来排序,下同
- childroot->setData(0, Qt::ToolTipRole, node.relativePath);
- m_fileAttris.append(node);
- WalkFileInfo oneDir(direction, childroot, namepath);
- dirsList.push_front(oneDir);
- }
- QDir dir_file(path);
- dir_file.setFilter(QDir::Files | QDir::NoDotAndDotDot | QDir::NoSymLinks);//获取当前所有文件
- QFileInfoList list_file = dir_file.entryInfoList();
- for (int i = 0; i < list_file.size(); ++i)
- { //将当前目录中所有文件添加到treewidget中
- QFileInfo fileInfo = list_file.at(i);
- QString name2 = fileInfo.fileName();
- QTreeWidgetItem* child = new QTreeWidgetItem(QStringList() << name2);
- child->setIcon(0, QIcon(":/Resources/img/point.png"));
- child->setText(1, getFileSizeFormat(fileInfo.size()));
- /*QString lastModifyTime = fileInfo.lastModified().toString("yy/MM/dd hh:mm:ss");
- child->setText(2, lastModifyTime);*/
- root->addChild(child);
- fileAttriNode node;
- node.type = RC_FILE;//是文件
- node.selfItem = child;
- node.parent = root;
- node.relativePath = fileInfo.absoluteFilePath();
- //把路径名称保存到tips中,后续需要这个来排序,下同
-
- child->setData(0, Qt::ToolTipRole, node.relativePath);
- m_fileAttris.append(node);
- }
- fileNums += list_file.size();
- }
- return fileNums;
- }
- int EncodeConvert::loadDir(QString rootDirPath)
- {
- QString rootpath = rootDirPath;
- QTreeWidgetItem* root = nullptr;
- int fileNums = 0;
- ui.treeWidget->setColumnWidth(0, 400);
- ui.treeWidget->clear();
-
- root = new QTreeWidgetItem(ui.treeWidget);
- root->setText(0, rootpath);
- root->setExpanded(true);
- //第一个节点是目录根节点
- fileAttriNode node;
- node.type = RC_DIR;//是目录
- node.selfItem = root;
- node.parent = nullptr;
- node.relativePath = ".";
- m_fileAttris.append(node);
- fileNums = allfile(root, rootpath);
-
-
- return fileNums;
- }
- QFuture<EncodeThreadParameter*> EncodeConvert::commitTask(std::function<EncodeThreadParameter* (EncodeThreadParameter*)> fun, EncodeThreadParameter* parameter)
- {
- /* 这里最开始准备使用信号提交多线程,但是发现std:;function无法使用槽函数机制,需要自己是实现元对象
- * 直接使用QtConcurrent::run机制,不仅简单许多,而且在网上看了资料
- */
- return QtConcurrent::run(fun, parameter);
- }
- //对比左右文件的大小,sha1值来判断文件是否相等
- QFuture<EncodeThreadParameter_*> EncodeConvert::checkFileCode(QString filePath, QTreeWidgetItem* item)
- {
- EncodeThreadParameter_* p = new EncodeThreadParameter_(filePath);
- p->item = item;
- //int 0相等 1 不等
- return commitTask([](EncodeThreadParameter_* parameter)->EncodeThreadParameter_*
- {
- parameter->code = CmpareMode::scanFileRealCode(parameter->filepath);
- return parameter;
- }
- , p);
- }
- CODE_ID EncodeConvert::convertFileToCode(QString& filePath, CODE_ID srcCode, CODE_ID dstCode)
- {
- if (srcCode == CODE_ID::UNKOWN)
- {
- return CODE_ID::UNKOWN;
- }
- QFile file(filePath);
- if (!file.open(QIODevice::ReadOnly | QIODevice::ExistingOnly))
- {
- return CODE_ID::UNKOWN;
- }
- QByteArray content = file.readAll();
- file.close();
- int skip = 0;
- switch (srcCode)
- {
- case UNKOWN:
- break;
- case ANSI:
- break;
- case UNICODE_LE:
- skip = 2;
- break;
- case UNICODE_BE:
- skip = 2;
- break;
- case UTF8_NOBOM:
- break;
- case UTF8_BOM:
- skip = 3;
- break;
- case GBK:
- break;
- default:
- break;
- }
- if (!file.open(QIODevice::WriteOnly | QIODevice::ExistingOnly | QIODevice::Truncate))
- {
- return CODE_ID::UNKOWN;
- }
- QByteArray text2Save;
- if (skip == 2 && content.size() >= 2)
- {
- text2Save = QByteArray(content.mid(2));
- }
- else if (skip == 3 && content.size() >= 3)
- {
- text2Save = QByteArray(content.mid(3));
- }
- else
- {
- text2Save = QByteArray(content);
- }
- QString textOut;
- Encode::tranStrToUNICODE(srcCode, text2Save.data(), text2Save.size(), textOut);
-
- if (dstCode != UNKOWN)
- {
- //QByteArray codeFlag = Encode::getEncodeStartFlagByte(dstCode);
- //20210822 发现大坑,转换到一定格式后,字符串前面自动带了标识,不需要再来检查一次
- //if (!codeFlag.isEmpty())
- //{
- // //先写入标识头
- // file.write(codeFlag);
- //}
- //如果编码是已知如下类型,则后续保存其它行时,不修改编码格式,继续按照原编码进行保存
- //前面已经设置过编码了,这里不需要再设置
- if (dstCode == CODE_ID::UTF8_BOM)
- {
- //自动转换不会带UTF-8 BOM,所以自己要在前面写个BOM头。这是一个例外。需要手动写入头
- //其他必然BL LE则不需要。
- QByteArray codeFlag = Encode::getEncodeStartFlagByte(dstCode);
- if (!codeFlag.isEmpty())
- {
- //先写入标识头
- file.write(codeFlag);
- }
- }
- if (textOut.length() > 0)
- {
- //保存时注意编码问题。这个tolocal已经带了字符BOM头了。只要UTF8_BOM不会带
- QByteArray t = textOut.toLocal8Bit();
- file.write(textOut.toLocal8Bit());
- }
- }
- file.close();
- return dstCode;
- }
- CODE_ID EncodeConvert::getComboBoxCode(int index){
- CODE_ID ret = CODE_ID::UNKOWN;
- if (index < CODE_END)
- {
- ret = (CODE_ID)index;
- }
- return ret;
- };
- QFuture<EncodeThreadParameter_*> EncodeConvert::convertFileCode(QString filePath, QTreeWidgetItem* item)
- {
- EncodeThreadParameter_* p = new EncodeThreadParameter_(filePath);
- p->item = item;
- CODE_ID srcCode = static_cast<CODE_ID>(item->data(0, ITEM_CODE).toInt());
- CODE_ID dstCode = getComboBoxCode(ui.codeToComboBox->currentIndex());
- //int 0相等 1 不等
- return commitTask([=](EncodeThreadParameter_* parameter)->EncodeThreadParameter_*
- {
- if (dstCode != CODE_ID::UNKOWN)
- {
- parameter->code = convertFileToCode(parameter->filepath, srcCode, dstCode);
- }
- else
- {
- parameter->code = UNKOWN;
- }
- return parameter;
- }
- , p);
- }
- //20220114 仅仅使用第一行失败编码还是不行,因为utf8和gbk其实有相同的编码范围。
- //如果识别第一行为gbk的,则直接使用gbk。但是如果识别为utf8的,则需要识别更多的文本内容,这样会更慢
- void EncodeConvert::scanFileCode()
- {
- m_finishCmpFileNums = 0;
- m_commitCmpFileNums = 0;
- ui.selectFileBt->setEnabled(false);
- ui.startBt->setEnabled(false);
- ui.closeBt->setEnabled(false);
- ui.logTextBrowser->clear();
- ui.logTextBrowser->append(tr("start scan file text code, please wait..."));
- for (QList<fileAttriNode>::iterator iter = m_fileAttris.begin(); iter != m_fileAttris.end(); ++iter)
- {
- if (iter->type == RC_DIR)
- {
- iter->selfItem->setText(2, QString("--"));
- }
- else if ((iter->type == RC_FILE) && DocTypeListView::isSupportExt(fileSuffix(iter->relativePath)))
- {
- QFutureWatcher<EncodeThreadParameter_*>* futureWatcher = new QFutureWatcher<EncodeThreadParameter_*>();
- QObject::connect(futureWatcher, &QFutureWatcher<EncodeThreadParameter_>::finished, this, &EncodeConvert::slot_scanFileCode);
- futureWatcher->setFuture(this->checkFileCode(iter->relativePath,iter->selfItem));
- ++m_commitCmpFileNums;
- }
- else
- {
- iter->selfItem->setText(2, tr("ignore"));
- }
- }
- int finishProcessRatio = 0;
- while (m_finishCmpFileNums < m_commitCmpFileNums)
- {
- int curProcessRatio = m_finishCmpFileNums * 100 / m_commitCmpFileNums;
- //没%5更新一下
- if (curProcessRatio - finishProcessRatio >= 5)
- {
- finishProcessRatio = curProcessRatio;
- ui.logTextBrowser->append(tr("please wait, total file %1,cur scan index %2, scan finish %3%").arg(m_commitCmpFileNums).arg(m_finishCmpFileNums).arg(curProcessRatio));
- }
- QCoreApplication::processEvents();
- }
- ui.logTextBrowser->append(tr("scan finished, total file %1").arg(m_commitCmpFileNums));
- ui.selectFileBt->setEnabled(true);
- ui.startBt->setEnabled(true);
- ui.closeBt->setEnabled(true);
- }
- //文件对比完毕,显示出文件是否意义,不一样则红色字符标识
- void EncodeConvert::slot_scanFileCode()
- {
- QFutureWatcher<EncodeThreadParameter_*>* s = dynamic_cast<QFutureWatcher<EncodeThreadParameter_*> *>(sender());
- EncodeThreadParameter_* result = s->result();
- //这里释放的内容,其实是在mode里面new出来的
- if (result != nullptr)
- {
- result->item->setText(2, Encode::getCodeNameById(result->code));
- result->item->setData(0, ITEM_CODE, result->code);
- delete result;
- result = nullptr;
- }
- delete s;
- s = nullptr;
- ++m_finishCmpFileNums;
- }
- void EncodeConvert::slot_startConvert()
- {
- int extComboBoxIndex = ui.extComboBox->currentIndex();
- CODE_ID dstCode = getComboBoxCode(ui.codeToComboBox->currentIndex());
- m_finishCmpFileNums = 0;
- m_commitCmpFileNums = 0;
- ui.logTextBrowser->clear();
- //如果编码是已知如下类型,则后续保存其它行时,不修改编码格式,继续按照原编码进行保存
- QString destCodeName = Encode::getQtCodecNameById(dstCode);
- if (destCodeName.isEmpty() || destCodeName == "unknown")
- {
- //这里永远不会走。因为界面上不会有未知选项
- assert(false);
- return;
- }
- else
- {
- QTextCodec::setCodecForLocale(QTextCodec::codecForName(destCodeName.toStdString().c_str()));
- }
- ui.selectFileBt->setEnabled(false);
- ui.codeToComboBox->setEditable(false);
- ui.closeBt->setEnabled(false);
- for (QList<fileAttriNode>::iterator iter = m_fileAttris.begin(); iter != m_fileAttris.end(); ++iter)
- {
- if ((iter->type == RC_FILE) && isSupportExt(extComboBoxIndex, fileSuffix(iter->relativePath)))
- {
- qDebug() << iter->relativePath;
- CODE_ID srcCode = static_cast<CODE_ID>(iter->selfItem->data(0, ITEM_CODE).toInt());
- CODE_ID dstCode = getComboBoxCode(ui.codeToComboBox->currentIndex());
- if (srcCode != dstCode)
- {
- QFutureWatcher<EncodeThreadParameter_*>* futureWatcher = new QFutureWatcher<EncodeThreadParameter_*>();
- QObject::connect(futureWatcher, &QFutureWatcher<EncodeThreadParameter_>::finished, this, &EncodeConvert::slot_convertFileFinish);
- futureWatcher->setFuture(this->convertFileCode(iter->relativePath, iter->selfItem));
- ++m_commitCmpFileNums;
- }
- else
- {
- iter->selfItem->setText(4, tr("already %1 ignore").arg(Encode::getCodeNameById(srcCode)));
- }
- }
- else
- {
- iter->selfItem->setText(4, tr("ignore"));
- }
- }
- int finishProcessRatio = 0;
- while (m_finishCmpFileNums < m_commitCmpFileNums)
- {
- int curProcessRatio = m_finishCmpFileNums * 100 / m_commitCmpFileNums;
- //没%5更新一下
- if (curProcessRatio - finishProcessRatio >= 5)
- {
- finishProcessRatio = curProcessRatio;
- ui.logTextBrowser->append(tr("total file %1,cur deal index %2,finish %3%").arg(m_commitCmpFileNums).arg(m_finishCmpFileNums).arg(curProcessRatio));
- }
- QCoreApplication::processEvents();
- }
- ui.logTextBrowser->append(tr("total file %1,cur deal index %2,finish 100%").arg(m_commitCmpFileNums).arg(m_finishCmpFileNums));
- ui.logTextBrowser->append(tr("convert finished !"));
- ui.selectFileBt->setEnabled(true);
- ui.codeToComboBox->setEditable(true);
- ui.closeBt->setEnabled(true);
- }
- //转换完成,设置当前表格上的显示状态
- void EncodeConvert::slot_convertFileFinish()
- {
- QFutureWatcher<EncodeThreadParameter_*>* s = dynamic_cast<QFutureWatcher<EncodeThreadParameter_*> *>(sender());
- EncodeThreadParameter_* result = s->result();
- //这里释放的内容,其实是在mode里面new出来的
- if (result != nullptr)
- {
- if (result->code != UNKOWN)
- {
- result->item->setText(3, Encode::getCodeNameById(result->code));
- result->item->setText(4, tr("convert finish"));
- }
- else
- {
- result->item->setText(4, tr("convert fail"));
- ui.logTextBrowser->append(tr("file %1 convert failed,pleas check...").arg(result->item->data(0, Qt::ToolTipRole).toString()));
- }
- result->item->setData(0, ITEM_CODE, result->code);
- delete result;
- result = nullptr;
- }
- delete s;
- s = nullptr;
- ++m_finishCmpFileNums;
- }
- //对item进行间隔着色
- void EncodeConvert::setItemIntervalBackground()
- {
- int curItemIndex = 0;
- QTreeWidgetItemIterator it(ui.treeWidget);
- while (*it) {
- if (curItemIndex % 2 == 1)
- {
- setItemBackground(*it, QColor(0xf8faf9));
- }
- ++it;
- ++curItemIndex;
- }
- }
- void EncodeConvert::setItemBackground(QTreeWidgetItem* item, const QColor& color)
- {
- QBrush b(color);
- item->setBackground(0, b);
- item->setBackground(1, b);
- item->setBackground(2, b);
- item->setBackground(3, b);
- item->setBackground(4, b);
- }
- void EncodeConvert::dragEnterEvent(QDragEnterEvent* event)
- {
- if (event->mimeData()->hasFormat("text/uri-list")) //只能打开文本文件
- {
- event->accept(); //可以在这个窗口部件上拖放对象
- }
- else
- {
- event->ignore();
- }
- }
- void EncodeConvert::dropEvent(QDropEvent* e)
- {
- QList<QUrl> urls = e->mimeData()->urls();
- if (urls.isEmpty())
- return;
- QString dirName = urls.first().toLocalFile();
- if (dirName.isEmpty())
- {
- return;
- }
- QDir dir(dirName);
- if (!dir.exists())
- {
- ui.logTextBrowser->append(tr("please drop a file dir ..."));
- return;
- }
- ui.treeWidget->clear();
- m_fileAttris.clear();
- loadDir(dirName);
- setItemIntervalBackground();
- scanFileCode();
- e->accept();
- }
|