-
Notifications
You must be signed in to change notification settings - Fork 37
Expand file tree
/
Copy pathsinglejob.cpp
More file actions
971 lines (842 loc) · 33.9 KB
/
singlejob.cpp
File metadata and controls
971 lines (842 loc) · 33.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
// Copyright (C) 2019 ~ 2020 Uniontech Software Technology Co.,Ltd.
// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: GPL-3.0-or-later
#include "singlejob.h"
#include "processopenthread.h"
#include "openwithdialog.h"
#include "datamanager.h"
#include "uitools.h"
#include <linux/limits.h>
#include <QUuid>
#include <QThread>
#include <QDebug>
#include <QDir>
// 工作线程
void SingleJobThread::run()
{
// qDebug() << "SingleJobThread started";
q->doWork(); // 在线程中执行操作
}
// 单个操作
SingleJob::SingleJob(ReadOnlyArchiveInterface *pInterface, QObject *parent)
: ArchiveJob(parent)
, m_pInterface(pInterface)
, d(new SingleJobThread(this))
{
qDebug() << "SingleJob instance created, interface:" << pInterface;
}
SingleJob::~SingleJob()
{
qDebug() << "SingleJob instance destroyed";
if (d->isRunning()) {
qDebug() << "Stopping worker thread";
d->quit(); // 线程安全退出,不能使用terminate强行退出
d->wait();
}
delete d;
}
void SingleJob::start()
{
qDebug() << "Starting job, type:" << m_eJobType;
jobTimer.start();
// 若插件指针为空,立即异常退出
if (nullptr == m_pInterface) {
qWarning() << "Interface is null, aborting job";
slotFinished(PFT_Error);
return;
}
// 判断是否通过线程的方式调用
if (m_pInterface->waitForFinished()) {
qDebug() << "Executing work directly";
doWork(); // 直接执行操作
} else {
qDebug() << "Starting worker thread";
d->start(); // 开启线程,执行操作
}
}
void SingleJob::doPause()
{
qDebug() << "Pausing job";
// 调用插件暂停接口
if (m_pInterface) {
qDebug() << "Calling interface pause operation";
m_pInterface->pauseOperation();
} else {
qWarning() << "Interface is null, cannot pause";
}
}
void SingleJob::doContinue()
{
qDebug() << "Resuming job";
// 调用插件继续接口
if (m_pInterface) {
qDebug() << "Calling interface continue operation";
m_pInterface->continueOperation();
} else {
qWarning() << "Interface is null, cannot continue";
}
}
bool SingleJob::status()
{
qDebug() << "Checking job status";
// 调用插件继续接口
if (m_pInterface) {
bool status = m_pInterface->status();
qDebug() << "Job status:" << status;
return status;
}
qWarning() << "Interface is null, returning false status";
return false;
}
SingleJobThread *SingleJob::getdptr()
{
qDebug() << "Getting worker thread pointer";
return d;
}
bool SingleJob::doKill()
{
qDebug() << "Killing job, type:" << m_eJobType;
if (nullptr == m_pInterface) {
qWarning() << "Interface is null, cannot kill job";
return false;
}
const bool killed = m_pInterface->doKill();
if (killed) {
qDebug() << "Job killed successfully";
return true;
}
if (d->isRunning()) { //Returns true if the thread is running
qInfo() << "Requesting graceful thread interruption, will abort in one second otherwise.";
d->requestInterruption(); //请求中断线程(建议性)
d->wait(1000); //阻塞1s或阻塞到线程结束(取小)
}
qDebug() << "Job kill completed";
return true;
}
void SingleJob::initConnections()
{
qDebug() << "Initializing signal connections";
connect(m_pInterface, &ReadOnlyArchiveInterface::signalFinished, this, &SingleJob::slotFinished, Qt::ConnectionType::UniqueConnection);
connect(m_pInterface, &ReadOnlyArchiveInterface::signalprogress, this, &SingleJob::signalprogress, Qt::ConnectionType::UniqueConnection);
connect(m_pInterface, &ReadOnlyArchiveInterface::signalCurFileName, this, &SingleJob::signalCurFileName, Qt::ConnectionType::UniqueConnection);
connect(m_pInterface, &ReadOnlyArchiveInterface::signalFileWriteErrorName, this, &SingleJob::signalFileWriteErrorName, Qt::ConnectionType::UniqueConnection);
connect(m_pInterface, &ReadOnlyArchiveInterface::signalQuery, this, &SingleJob::signalQuery, Qt::ConnectionType::AutoConnection);
connect(m_pInterface, &ReadOnlyArchiveInterface::error, this, &SingleJob::slotError, Qt::AutoConnection);
qDebug() << "Signal connections initialized";
}
void SingleJob::slotFinished(PluginFinishType eType)
{
qInfo() << "Job finished, type:" << m_eJobType
<< ", result:" << eType
<< ", time:" << jobTimer.elapsed() << "ms";
m_eFinishedType = eType;
if (m_pInterface) {
m_eErrorType = m_pInterface->errorType();
qDebug() << "Error type:" << m_eErrorType;
}
emit signalJobFinshed();
}
void SingleJob::slotError(const QString &message, const QString &details)
{
Q_UNUSED(details);
// 传递临时消息信号,用于显示但不中断操作的非致命错误提示
emit signalTempMessage(message);
}
// 加载操作
LoadJob::LoadJob(ReadOnlyArchiveInterface *pInterface, QObject *parent)
: SingleJob(pInterface, parent)
{
qDebug() << "LoadJob instance created";
m_eJobType = JT_Load;
initConnections();
}
LoadJob::~LoadJob()
{
qDebug() << "LoadJob instance destroyed";
}
void LoadJob::doWork()
{
qDebug() << "LoadJob starting work";
if (m_pInterface) {
PluginFinishType eType = m_pInterface->list();
qDebug() << "List operation completed, result:" << eType;
if (!(m_pInterface->waitForFinished())) {
qDebug() << "Emitting finished signal";
slotFinished(eType);
}
} else {
qWarning() << "Interface is null in LoadJob";
}
}
// 压缩操作
AddJob::AddJob(const QList<FileEntry> &files, ReadOnlyArchiveInterface *pInterface, const CompressOptions &options, QObject *parent)
: SingleJob(pInterface, parent)
, m_vecFiles(files)
, m_stCompressOptions(options)
{
initConnections();
m_eJobType = JT_Add;
}
AddJob::~AddJob()
{
}
void AddJob::doWork()
{
qDebug() << "AddJob starting work, files count:" << m_vecFiles.size();
ReadWriteArchiveInterface *pWriteInterface = dynamic_cast<ReadWriteArchiveInterface *>(m_pInterface);
if (nullptr == pWriteInterface) {
qWarning() << "Failed to cast to ReadWriteArchiveInterface";
return;
}
PluginFinishType eType = pWriteInterface->addFiles(m_vecFiles, m_stCompressOptions);
qDebug() << "Add files operation completed, result:" << eType;
if (!(pWriteInterface->waitForFinished())) {
qDebug() << "Emitting finished signal";
slotFinished(eType);
}
}
// 创建压缩包操作
CreateJob::CreateJob(const QList<FileEntry> &files, ReadOnlyArchiveInterface *pInterface, const CompressOptions &options, QObject *parent)
: SingleJob(pInterface, parent)
, m_vecFiles(files)
, m_stCompressOptions(options)
{
initConnections();
m_eJobType = JT_Create;
}
CreateJob::~CreateJob()
{
}
void CreateJob::doWork()
{
qDebug() << "CreateJob starting work, files count:" << m_vecFiles.size();
ReadWriteArchiveInterface *pWriteInterface = dynamic_cast<ReadWriteArchiveInterface *>(m_pInterface);
if (pWriteInterface == nullptr) {
qWarning() << "Failed to cast to ReadWriteArchiveInterface";
return;
}
// 调用压缩接口
PluginFinishType eType = pWriteInterface->addFiles(m_vecFiles, m_stCompressOptions);
qDebug() << "Create archive operation completed, result:" << eType;
if (!(pWriteInterface->waitForFinished())) {
qDebug() << "Emitting finished signal";
slotFinished(eType);
}
}
bool CreateJob::doKill()
{
qDebug() << "CreateJob doKill";
if (nullptr == m_pInterface) {
qDebug() << "CreateJob doKill, interface is null";
return false;
}
const bool killed = m_pInterface->doKill();
if (killed) {
qDebug() << "CreateJob doKill, interface killed";
cleanCompressFileCancel();
return true;
}
if (d->isRunning()) { //Returns true if the thread is running
qInfo() << "Requesting graceful thread interruption, will abort in one second otherwise.";
d->requestInterruption(); //请求中断线程(建议性)
d->wait(1000); //阻塞1s或阻塞到线程结束(取小)
}
cleanCompressFileCancel();
return true;
}
void CreateJob::cleanCompressFileCancel()
{
qDebug() << "CreateJob cleanCompressFileCancel";
if (m_stCompressOptions.bSplit) {
qDebug() << "CreateJob cleanCompressFileCancel, split compress";
// 判断 7z分卷压缩的 文件名
QFileInfo file(dynamic_cast<ReadWriteArchiveInterface *>(m_pInterface)->getArchiveName());
QStringList nameFilters;
nameFilters << file.fileName() + ".0*";
QDir dir(file.path());
QFileInfoList files = dir.entryInfoList(nameFilters, QDir::Files | QDir::Readable, QDir::Name);
foreach (QFileInfo fi, files) {
QFile fiRemove(fi.filePath());
if (fiRemove.exists()) {
qInfo() << "取消时删除:" << fiRemove.fileName();
fiRemove.remove();
}
}
} else {
qDebug() << "CreateJob cleanCompressFileCancel, not split compress";
QFile fiRemove(dynamic_cast<ReadWriteArchiveInterface *>(m_pInterface)->getArchiveName()); // 没有判断 7z分卷压缩的 文件名
if (fiRemove.exists()) {
qInfo() << "取消时删除:" << fiRemove.fileName();
fiRemove.remove();
}
}
}
// 解压操作
ExtractJob::ExtractJob(const QList<FileEntry> &files, ReadOnlyArchiveInterface *pInterface, const ExtractionOptions &options, QObject *parent)
: SingleJob(pInterface, parent)
, m_vecFiles(files)
, m_stExtractionOptions(options)
{
qDebug() << "ExtractJob constructor";
initConnections();
m_eJobType = JT_Extract;
}
ExtractJob::~ExtractJob()
{
qDebug() << "ExtractJob instance destroyed";
}
void ExtractJob::doWork()
{
qDebug() << "ExtractJob starting work, files count:" << m_vecFiles.size();
if (m_pInterface) {
PluginFinishType eType = m_pInterface->extractFiles(m_vecFiles, m_stExtractionOptions);
qDebug() << "Extract operation completed, result:" << eType;
if (!(m_pInterface->waitForFinished())) {
qDebug() << "Emitting finished signal";
slotFinished(eType);
} else {
if (PFT_Error == eType) {
qWarning() << "Extract operation failed";
errorcode = false;
}
}
} else {
qWarning() << "Interface is null in ExtractJob";
}
}
// 删除操作
DeleteJob::DeleteJob(const QList<FileEntry> &files, ReadOnlyArchiveInterface *pInterface, QObject *parent)
: SingleJob(pInterface, parent)
, m_vecFiles(files)
{
qDebug() << "DeleteJob constructor";
m_eJobType = JT_Delete;
initConnections();
m_eJobType = JT_Delete;
}
DeleteJob::~DeleteJob()
{
qDebug() << "DeleteJob instance destroyed";
}
void DeleteJob::doWork()
{
qDebug() << "DeleteJob starting work, files count:" << m_vecFiles.size();
ReadWriteArchiveInterface *pWriteInterface = dynamic_cast<ReadWriteArchiveInterface *>(m_pInterface);
if (nullptr == pWriteInterface) {
qWarning() << "Failed to cast to ReadWriteArchiveInterface in DeleteJob";
return;
}
PluginFinishType eType = pWriteInterface->deleteFiles(m_vecFiles);
if (!(pWriteInterface->waitForFinished())) {
qDebug() << "Emitting finished signal";
slotFinished(eType);
}
}
// 重命名操作
RenameJob::RenameJob(const QList<FileEntry> &files, ReadOnlyArchiveInterface *pInterface, QObject *parent)
: SingleJob(pInterface, parent)
, m_vecFiles(files)
{
qDebug() << "RenameJob constructor";
initConnections();
m_eJobType = JT_Rename;
}
RenameJob::~RenameJob()
{
qDebug() << "RenameJob instance destroyed";
}
void RenameJob::doWork()
{
qDebug() << "RenameJob starting work, files count:" << m_vecFiles.size();
ReadWriteArchiveInterface *pWriteInterface = dynamic_cast<ReadWriteArchiveInterface *>(m_pInterface);
if (nullptr == pWriteInterface) {
qWarning() << "Failed to cast to ReadWriteArchiveInterface in RenameJob";
return;
}
PluginFinishType eType = pWriteInterface->renameFiles(m_vecFiles);
qDebug() << "Rename operation completed, result:" << eType;
if (!(pWriteInterface->waitForFinished())) {
qDebug() << "Emitting finished signal";
slotFinished(eType);
} else {
qDebug() << "Rename operation completed synchronously";
}
}
OpenJob::OpenJob(const FileEntry &stEntry, const QString &strTempExtractPath, const QString &strProgram, ReadOnlyArchiveInterface *pInterface, QObject *parent)
: SingleJob(pInterface, parent)
, m_stEntry(stEntry)
, m_strTempExtractPath(strTempExtractPath)
, m_strProgram(strProgram)
{
qDebug() << "OpenJob instance created for file:" << stEntry.strFileName;
m_eJobType = JT_Open;
connect(m_pInterface, &ReadOnlyArchiveInterface::signalFinished, this, &OpenJob::slotFinished, Qt::ConnectionType::UniqueConnection);
connect(m_pInterface, &ReadOnlyArchiveInterface::signalQuery, this, &SingleJob::signalQuery, Qt::ConnectionType::AutoConnection);
connect(m_pInterface, &ReadOnlyArchiveInterface::error, this, &SingleJob::slotError, Qt::AutoConnection);
}
OpenJob::~OpenJob()
{
qDebug() << "OpenJob instance destroyed";
}
void OpenJob::doWork()
{
qDebug() << "OpenJob starting work for file:" << m_stEntry.strFileName;
if (m_pInterface) {
// 构建解压参数
ExtractionOptions options;
options.bOpen = true;
options.strTargetPath = m_strTempExtractPath;
// 当作提取,去除父目录
if (m_stEntry.strFullPath.contains(QDir::separator())) {
qDebug() << "Setting destination for nested file";
int iIndex = m_stEntry.strFullPath.lastIndexOf(QDir::separator());
if (iIndex > 0)
options.strDestination = m_stEntry.strFullPath.left(iIndex + 1); // 当前路径截掉最后一级目录(保留'/')
}
options.qSize = m_stEntry.qSize;
PluginFinishType eType = m_pInterface->extractFiles(QList<FileEntry>() << m_stEntry, options);
qDebug() << "Open extraction operation completed, result:" << eType;
if (!(m_pInterface->waitForFinished())) {
qDebug() << "Emitting finished signal";
slotFinished(eType);
} else {
qDebug() << "Open extraction completed synchronously";
}
} else {
qWarning() << "Interface is null in OpenJob";
}
}
void OpenJob::slotFinished(PluginFinishType eType)
{
qDebug() << "OpenJob finished with type:" << eType;
if (PFT_Nomral == eType) {
qDebug() << "Processing file for opening";
QString name = m_stEntry.strFileName;
//对于超长文件打开失败问题处理
QString strTempFileName = m_stEntry.strFileName;
if (NAME_MAX < QString(strTempFileName).toLocal8Bit().length() && !strTempFileName.endsWith(QDir::separator())) {
qDebug() << "Handling long filename";
QString strTemp = strTempFileName.left(60);
name = strTemp + QString("(%1)").arg(1, 3, 10, QChar('0'))+"." + QFileInfo(strTempFileName).completeSuffix();
}
if (name.contains("%")) { // 文件名含有%的时候无法直接双击打开, 创建一个该文件的链接,文件名不含有%,通过打开链接打开源文件
qDebug() << "Creating link for file with % in name";
name = m_strTempExtractPath + QDir::separator() + name.replace("%", "1"); // 将文件名中的%替换为1;
if (!QFile::link(m_stEntry.strFileName, name)) { // 创建链接
qWarning() << "Failed to create link for file";
return;
}
} else {
name = m_strTempExtractPath + QDir::separator() + name;
}
// 在线程中执行外部应用打开的命令
qDebug() << "Starting external process to open file:" << name;
ProcessOpenThread *p = new ProcessOpenThread;
p->setProgramPath(OpenWithDialog::getProgramPathByExec(m_strProgram));
p->setArguments(QStringList() << name);
p->start();
} else {
qWarning() << "Failed to open file, type:" << eType;
}
SingleJob::slotFinished(eType); // 在结束上述操作之后发送job结束信号
}
UpdateJob::UpdateJob(const UpdateOptions &options, ReadOnlyArchiveInterface *pInterface, QObject *parent)
: SingleJob(pInterface, parent)
, m_stOptions(options)
{
qDebug() << "UpdateJob instance created";
m_eJobType = JT_Update;
//connect(m_pInterface, &ReadOnlyArchiveInterface::signalFinished, this, &UpdateJob::slotFinished, Qt::ConnectionType::UniqueConnection);
}
UpdateJob::~UpdateJob()
{
qDebug() << "UpdateJob instance destroyed";
}
void UpdateJob::start()
{
qDebug() << "Starting UpdateJob";
jobTimer.start();
// 若插件指针为空,立即异常退出
if (nullptr == m_pInterface) {
qWarning() << "Interface is null in UpdateJob";
slotFinished(PFT_Error);
return;
}
d->start(); // 开启线程,执行操作
}
void UpdateJob::doWork()
{
qDebug() << "UpdateJob starting work";
ReadWriteArchiveInterface *pWriteInterface = dynamic_cast<ReadWriteArchiveInterface *>(m_pInterface);
if (pWriteInterface) {
qDebug() << "Calling updateArchiveData";
// 调用更新函数
PluginFinishType eType = pWriteInterface->updateArchiveData(m_stOptions);
qDebug() << "Update operation completed, result:" << eType;
//if (!(pWriteInterface->waitForFinished())) {
slotFinished(eType);
//}
} else {
qWarning() << "Failed to cast to ReadWriteArchiveInterface in UpdateJob";
}
}
CommentJob::CommentJob(const QString &strComment, ReadOnlyArchiveInterface *pInterface, QObject *parent)
: SingleJob(pInterface, parent)
, m_strComment(strComment)
{
qDebug() << "CommentJob instance created with comment length:" << strComment.length();
m_eJobType = JT_Comment;
// 进度和结束处理
connect(m_pInterface, &ReadOnlyArchiveInterface::signalFinished, this, &CommentJob::slotFinished, Qt::ConnectionType::UniqueConnection);
connect(m_pInterface, &ReadOnlyArchiveInterface::signalprogress, this, &CommentJob::signalprogress, Qt::ConnectionType::UniqueConnection);
}
CommentJob::~CommentJob()
{
qDebug() << "CommentJob instance destroyed";
if (m_pInterface) {
delete m_pInterface;
m_pInterface = nullptr;
}
}
void CommentJob::doWork()
{
qDebug() << "CommentJob starting work";
qInfo() << "Adding comment";
ReadWriteArchiveInterface *pWriteInterface = dynamic_cast<ReadWriteArchiveInterface *>(m_pInterface);
if (pWriteInterface) {
PluginFinishType eType = pWriteInterface->addComment(m_strComment);
qDebug() << "Add comment operation completed, result:" << eType;
if (!(pWriteInterface->waitForFinished())) {
qDebug() << "Emitting finished signal";
slotFinished(eType);
} else {
qDebug() << "Comment operation completed synchronously";
}
} else {
qWarning() << "Failed to cast to ReadWriteArchiveInterface in CommentJob";
}
}
ComplexJob::ComplexJob(const QString strOriginalArchiveFullPath, QObject *parent)
: ArchiveJob(parent)
, m_strOriginalArchiveFullPath(strOriginalArchiveFullPath)
{
qDebug() << "ComplexJob instance created for:" << strOriginalArchiveFullPath;
}
ComplexJob::~ComplexJob()
{
qDebug() << "ComplexJob instance destroyed";
if (m_pIface) {
delete m_pIface;
m_pIface = nullptr;
}
}
void ComplexJob::doPause()
{
qDebug() << "Pausing ComplexJob";
// 调用插件暂停接口
if (m_pIface) {
qDebug() << "Calling interface pause operation";
m_pIface->pauseOperation();
} else {
qWarning() << "Interface is null, cannot pause";
}
}
void ComplexJob::doContinue()
{
qDebug() << "Continuing ComplexJob";
// 调用插件继续接口
if (m_pIface) {
qDebug() << "Calling interface continue operation";
m_pIface->continueOperation();
} else {
qWarning() << "Interface is null, cannot continue";
}
}
bool ComplexJob::doKill()
{
qDebug() << "Killing ComplexJob";
if (m_pIface) {
return m_pIface->doKill();
}
qWarning() << "Interface is null, cannot kill";
return false;
}
void ComplexJob::slotHandleSingleJobProgress(double dPercentage)
{
if (0 == m_iStepNo) { // 解压进度
qDebug() << "Extract step progress:" << dPercentage;
emit signalprogress(dPercentage * 0.3);
} else { // 压缩进度
qDebug() << "Compress step progress:" << dPercentage;
emit signalprogress(30 + dPercentage * 0.7);
}
}
void ComplexJob::slotHandleSingleJobCurFileName(const QString &strName)
{
qDebug() << "Current file in complex job:" << strName;
emit signalCurFileName(strName);
}
ConvertJob::ConvertJob(const QString strOriginalArchiveFullPath, const QString strTargetFullPath, const QString strNewArchiveFullPath, QObject *parent)
: ComplexJob(strOriginalArchiveFullPath, parent)
, m_strTargetFullPath(strTargetFullPath)
, m_strNewArchiveFullPath(strNewArchiveFullPath)
{
qDebug() << "ConvertJob instance created from:" << strOriginalArchiveFullPath << "to:" << strNewArchiveFullPath;
m_eJobType = JT_Convert;
}
ConvertJob::~ConvertJob()
{
qDebug() << "ConvertJob instance destroyed";
SAFE_DELETE_ELE(m_pCreateJob)
SAFE_DELETE_ELE(m_pExtractJob);
}
void ConvertJob::start()
{
qDebug() << "Starting ConvertJob";
ReadOnlyArchiveInterface *pIface = UiTools::createInterface(m_strOriginalArchiveFullPath);
if (pIface) {
qInfo() << "格式转换开始解压";
m_pIface = pIface;
m_iStepNo = 0;
// 创建解压参数
QFileInfo file(m_strOriginalArchiveFullPath);
ExtractionOptions stOptions;
stOptions.strTargetPath = m_strTargetFullPath;
stOptions.qComressSize = file.size();
stOptions.bAllExtract = true;
// 创建解压操作
qDebug() << "Creating ExtractJob for conversion";
m_pExtractJob = new ExtractJob(QList<FileEntry>(), pIface, stOptions);
connect(m_pExtractJob, &ExtractJob::signalprogress, this, &ConvertJob::slotHandleSingleJobProgress);
connect(m_pExtractJob, &ExtractJob::signalCurFileName, this, &ConvertJob::slotHandleSingleJobCurFileName);
connect(m_pExtractJob, &ExtractJob::signalQuery, this, &ConvertJob::signalQuery);
connect(m_pExtractJob, &ExtractJob::signalJobFinshed, this, &ConvertJob::slotHandleExtractFinished);
m_pExtractJob->doWork();
} else {
qWarning() << "Failed to create interface for conversion";
}
}
void ConvertJob::slotHandleExtractFinished()
{
qDebug() << "Extract step finished in ConvertJob";
// 解压结束
if (m_pExtractJob) {
m_eFinishedType = m_pExtractJob->m_eFinishedType;
m_eErrorType = m_pExtractJob->m_eErrorType;
qDebug() << "Extract finished with type:" << m_eFinishedType;
switch (m_eFinishedType) {
// 正常结束之后,进行压缩操作
case PFT_Nomral: {
qInfo() << "格式转换开始压缩";
m_iStepNo = 1;
ReadOnlyArchiveInterface *pIface = UiTools::createInterface(m_strNewArchiveFullPath, true);
if (pIface) {
qDebug() << "Creating interface for compression step";
SAFE_DELETE_ELE(m_pIface);
m_pIface = pIface;
QList<FileEntry> listEntry;
// 在临时路径里面获取待压缩文件
QDir dir(m_strTargetFullPath);
QFileInfoList fileList = dir.entryInfoList(QDir::AllEntries | QDir::System
| QDir::NoDotAndDotDot | QDir::NoSymLinks
| QDir::Hidden);
qDebug() << "Found" << fileList.size() << "files to compress";
foreach (QFileInfo strFile, fileList) {
FileEntry stFileEntry;
stFileEntry.strFullPath = strFile.filePath();
listEntry.push_back(stFileEntry);
}
// 构建压缩参数
CompressOptions options;
options.iCompressionLevel = 3; // 默认压缩等级为3,其余参数均为默认选项
options.qTotalSize = DataManager::get_instance().archiveData().qSize; // list压缩包时存储的压缩包内文件实际总大小
// 创建压缩操作
qDebug() << "Creating CreateJob for compression";
m_pCreateJob = new CreateJob(listEntry, pIface, options);
connect(m_pCreateJob, &CreateJob::signalprogress, this, &ConvertJob::slotHandleSingleJobProgress);
connect(m_pCreateJob, &CreateJob::signalCurFileName, this, &ConvertJob::slotHandleSingleJobCurFileName);
connect(m_pCreateJob, &CreateJob::signalJobFinshed, this, &ConvertJob::signalJobFinshed);
m_pCreateJob->doWork();
} else {
qWarning() << "Failed to create interface for compression step";
}
}
break;
// 用户取消之后,不进行压缩
case PFT_Cancel: {
qInfo() << "取消格式转换";
emit signalJobFinshed();
}
break;
// 出现错误的情况,提示用户
case PFT_Error: {
qInfo() << "格式转换错误";
emit signalJobFinshed();
}
break;
}
} else {
qWarning() << "No extract job to handle";
}
}
StepExtractJob::StepExtractJob(const QString strOriginalArchiveFullPath, const ExtractionOptions &stOptions, QObject *parent)
: ComplexJob(strOriginalArchiveFullPath, parent)
, m_stExtractionOptions(stOptions)
{
qDebug() << "StepExtractJob instance created for:" << strOriginalArchiveFullPath;
m_eJobType = JT_StepExtract;
}
StepExtractJob::~StepExtractJob()
{
qDebug() << "StepExtractJob instance destroyed";
}
void StepExtractJob::start()
{
qDebug() << "Starting StepExtractJob";
// tar.7z 指定使用cli7zplugin先解压出tar包
ReadOnlyArchiveInterface *pIface = UiTools::createInterface(m_strOriginalArchiveFullPath, false);
if (nullptr != pIface) {
qInfo() << "StepExtractJob: 开始解压tar.7z成tar";
m_pIface = pIface;
m_iStepNo = 0;
// 设置解压临时路径
QFileInfo file(m_strOriginalArchiveFullPath);
QString strProcessID = QString::number(QCoreApplication::applicationPid()); // 获取应用进程号
m_strTempFilePath = QStandardPaths::writableLocation(QStandardPaths::TempLocation)
+ QDir::separator() + strProcessID + QDir::separator()
+ QUuid::createUuid().toString(QUuid::Id128);
qDebug() << "Temp extraction path:" << m_strTempFilePath;
// 创建解压参数
ExtractionOptions stOptions;
stOptions.strTargetPath = m_strTempFilePath;
stOptions.qComressSize = file.size();
stOptions.bAllExtract = true;
// 创建解压操作
qDebug() << "Creating first ExtractJob for tar.7z";
m_pExtractJob = new ExtractJob(QList<FileEntry>(), pIface, stOptions, this);
connect(m_pExtractJob, &ExtractJob::signalprogress, this, &StepExtractJob::slotHandleSingleJobProgress);
connect(m_pExtractJob, &ExtractJob::signalCurFileName, this, &StepExtractJob::slotHandleSingleJobCurFileName);
connect(m_pExtractJob, &ExtractJob::signalQuery, this, &StepExtractJob::signalQuery);
connect(m_pExtractJob, &ExtractJob::signalJobFinshed, this, &StepExtractJob::slotHandleExtractFinished);
m_pExtractJob->start();
} else {
qWarning() << "Failed to create interface for StepExtractJob";
}
}
void StepExtractJob::slotHandleExtractFinished()
{
qDebug() << "Step extract finished handler called";
// 解压结束
if (nullptr != m_pExtractJob) {
m_eFinishedType = m_pExtractJob->m_eFinishedType;
m_eErrorType = m_pExtractJob->m_eErrorType;
qDebug() << "Extract finished with type:" << m_eFinishedType;
switch (m_eFinishedType) {
// 正常结束之后,进行压缩操作
case PFT_Nomral: {
qDebug() << "Extract completed successfully, checking temp files";
// 获取临时解压文件
QDir dir(m_strTempFilePath);
if (!dir.exists()) {
qWarning() << "Temp directory does not exist";
return;
}
QFileInfoList list = dir.entryInfoList(QDir::AllEntries | QDir::System
| QDir::NoDotAndDotDot | QDir::Hidden);
qDebug() << "Found" << list.count() << "files in temp directory";
/***tar.7z格式压缩流程特殊处理***
* 1、tar.7z本质上就是一个tar包压缩成7z包,类型依然是x-7z-compressed
* 2、只针对7z里只有一个tar包的解压才做特殊处理,即直接解压出tar包内的文件
* 3、对于7z里有多个文件或唯一文件不是tar包的情况,解压不做特殊处理
* 4、后缀不为tar.7z,解压不做特殊处理
*/
if (1 == list.count()
&& list.at(0).filePath().endsWith(".tar")
&& determineMimeType(list.at(0).filePath()).name() == QLatin1String("application/x-tar")) {
qDebug() << "Found single tar file, proceeding with special handling";
QFileInfo fileInfo = list.at(0);
ReadOnlyArchiveInterface *pIface = UiTools::createInterface(fileInfo.absoluteFilePath(), false);
if (nullptr != pIface) {
qInfo() << "StepExtractJob: 开始解压tar";
SAFE_DELETE_ELE(m_pIface);
m_pIface = pIface;
m_iStepNo = 1;
// 创建解压参数
ExtractionOptions stOptions = m_stExtractionOptions;
stOptions.qComressSize = fileInfo.size();
stOptions.qSize = fileInfo.size();
stOptions.bAllExtract = true;
stOptions.bTar_7z = false;
// 创建解压操作
qDebug() << "Creating second ExtractJob for tar file";
m_pExtractJob2 = new ExtractJob(QList<FileEntry>(), pIface, stOptions, this);
connect(m_pExtractJob2, &ExtractJob::signalprogress, this, &StepExtractJob::slotHandleSingleJobProgress);
connect(m_pExtractJob2, &ExtractJob::signalCurFileName, this, &StepExtractJob::slotHandleSingleJobCurFileName);
connect(m_pExtractJob2, &ExtractJob::signalQuery, this, &StepExtractJob::signalQuery);
connect(m_pExtractJob2, &ExtractJob::signalJobFinshed, this, &StepExtractJob::signalJobFinshed);
m_pExtractJob2->start();
} else {
qWarning() << "Failed to create interface for tar file";
}
} else {
qDebug() << "Using fallback extraction method";
ReadOnlyArchiveInterface *pIface = UiTools::createInterface(m_strOriginalArchiveFullPath, false);
if (nullptr != pIface) {
qInfo() << "StepExtractJob: 开始直接解压原文件";
SAFE_DELETE_ELE(m_pIface);
m_pIface = pIface;
m_iStepNo = 1;
// 创建解压参数
ExtractionOptions stOptions = m_stExtractionOptions;
stOptions.password = DataManager::get_instance().archiveData().strPassword; // 第二次解压使用第一次保存的密码
stOptions.bAllExtract = true;
stOptions.bTar_7z = false;
// 创建解压操作
qDebug() << "Creating fallback ExtractJob";
m_pExtractJob2 = new ExtractJob(QList<FileEntry>(), pIface, stOptions, this);
connect(m_pExtractJob2, &ExtractJob::signalprogress, this, &StepExtractJob::slotHandleSingleJobProgress);
connect(m_pExtractJob2, &ExtractJob::signalCurFileName, this, &StepExtractJob::slotHandleSingleJobCurFileName);
connect(m_pExtractJob2, &ExtractJob::signalQuery, this, &StepExtractJob::signalQuery);
connect(m_pExtractJob2, &ExtractJob::signalJobFinshed, this, &StepExtractJob::signalJobFinshed);
m_pExtractJob2->start();
} else {
qWarning() << "Failed to create interface for fallback extraction";
}
}
}
break;
// 用户取消之后,不进行压缩
case PFT_Cancel: {
qInfo() << "Step extract cancelled";
emit signalJobFinshed();
}
break;
// 出现错误的情况,提示用户
case PFT_Error: {
qInfo() << "Step extract error";
emit signalJobFinshed();
}
break;
}
} else {
qWarning() << "No extract job to handle";
}
}
bool StepExtractJob::doKill()
{
qDebug() << "Killing StepExtractJob";
if (m_pIface) {
const bool killed = m_pIface->doKill();
if (killed) {
qDebug() << "StepExtractJob killed successfully";
return true;
}
}
if (m_pExtractJob2 && m_pExtractJob2->getdptr()->isRunning()) { //Returns true if the thread is running
qInfo() << "Requesting graceful thread interruption, will abort in one second otherwise.";
m_pExtractJob2->getdptr()->requestInterruption(); //请求中断线程(建议性)
m_pExtractJob2->getdptr()->wait(1000); //阻塞1s或阻塞到线程结束(取小)
}
return true;
}