File indexing completed on 2024-03-24 15:35:15

0001 /*
0002     This file is or will be part of KDE desktop environment
0003     SPDX-FileCopyrightText: 1999 Matt Koss <koss@miesto.sk>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-only
0006 */
0007 
0008 #include "kioworkertest.h"
0009 
0010 #include "../src/utils_p.h"
0011 
0012 #include <kio/copyjob.h>
0013 #include <kio/deletejob.h>
0014 #include <kio/listjob.h>
0015 #include <kio/mimetypejob.h>
0016 #include <kio/mkdirjob.h>
0017 #include <kio/simplejob.h>
0018 #include <kio/statjob.h>
0019 #include <kio/transferjob.h>
0020 #include <kprotocolinfo.h>
0021 
0022 // QT_STAT_LNK on Windows
0023 #include "kioglobal_p.h"
0024 
0025 #include <KJobUiDelegate>
0026 
0027 #include <QApplication>
0028 #include <QCommandLineOption>
0029 #include <QCommandLineParser>
0030 #include <QDebug>
0031 #include <QDir>
0032 #include <QGroupBox>
0033 #include <QLayout>
0034 #include <QLocale>
0035 #include <QMessageBox>
0036 #include <QStatusBar>
0037 #include <QThread>
0038 #include <QTimer>
0039 #include <QUrl>
0040 #include <qplatformdefs.h>
0041 
0042 using namespace KIO;
0043 
0044 KioWorkerTest::KioWorkerTest(QString src, QString dest, uint op, uint pr)
0045     : KMainWindow(nullptr)
0046 {
0047     job = nullptr;
0048 
0049     main_widget = new QWidget(this);
0050     QBoxLayout *topLayout = new QVBoxLayout(main_widget);
0051 
0052     QGridLayout *grid = new QGridLayout();
0053     topLayout->addLayout(grid);
0054 
0055     grid->setRowStretch(0, 1);
0056     grid->setRowStretch(1, 1);
0057 
0058     grid->setColumnStretch(0, 1);
0059     grid->setColumnStretch(1, 100);
0060 
0061     lb_from = new QLabel(QStringLiteral("From:"), main_widget);
0062     grid->addWidget(lb_from, 0, 0);
0063 
0064     le_source = new QLineEdit(main_widget);
0065     grid->addWidget(le_source, 0, 1);
0066     le_source->setText(src);
0067 
0068     lb_to = new QLabel(QStringLiteral("To:"), main_widget);
0069     grid->addWidget(lb_to, 1, 0);
0070 
0071     le_dest = new QLineEdit(main_widget);
0072     grid->addWidget(le_dest, 1, 1);
0073     le_dest->setText(dest);
0074 
0075     // Operation groupbox & buttons
0076     opButtons = new QButtonGroup(main_widget);
0077     QGroupBox *box = new QGroupBox(QStringLiteral("Operation"), main_widget);
0078     topLayout->addWidget(box, 10);
0079     connect(opButtons, qOverload<QAbstractButton *>(&QButtonGroup::buttonClicked), this, &KioWorkerTest::changeOperation);
0080 
0081     QBoxLayout *hbLayout = new QHBoxLayout(box);
0082 
0083     rbList = new QRadioButton(QStringLiteral("List"), box);
0084     opButtons->addButton(rbList);
0085     hbLayout->addWidget(rbList, 5);
0086 
0087     rbListRecursive = new QRadioButton(QStringLiteral("ListRecursive"), box);
0088     opButtons->addButton(rbListRecursive);
0089     hbLayout->addWidget(rbListRecursive, 5);
0090 
0091     rbStat = new QRadioButton(QStringLiteral("Stat"), box);
0092     opButtons->addButton(rbStat);
0093     hbLayout->addWidget(rbStat, 5);
0094 
0095     rbGet = new QRadioButton(QStringLiteral("Get"), box);
0096     opButtons->addButton(rbGet);
0097     hbLayout->addWidget(rbGet, 5);
0098 
0099     rbPut = new QRadioButton(QStringLiteral("Put"), box);
0100     opButtons->addButton(rbPut);
0101     hbLayout->addWidget(rbPut, 5);
0102 
0103     rbCopy = new QRadioButton(QStringLiteral("Copy"), box);
0104     opButtons->addButton(rbCopy);
0105     hbLayout->addWidget(rbCopy, 5);
0106 
0107     rbMove = new QRadioButton(QStringLiteral("Move"), box);
0108     opButtons->addButton(rbMove);
0109     hbLayout->addWidget(rbMove, 5);
0110 
0111     rbDelete = new QRadioButton(QStringLiteral("Delete"), box);
0112     opButtons->addButton(rbDelete);
0113     hbLayout->addWidget(rbDelete, 5);
0114 
0115     rbMkdir = new QRadioButton(QStringLiteral("Mkdir"), box);
0116     opButtons->addButton(rbMkdir);
0117     hbLayout->addWidget(rbMkdir, 5);
0118 
0119     rbMimetype = new QRadioButton(QStringLiteral("Mimetype"), box);
0120     opButtons->addButton(rbMimetype);
0121     hbLayout->addWidget(rbMimetype, 5);
0122 
0123     QAbstractButton *b = opButtons->buttons()[op];
0124     b->setChecked(true);
0125     changeOperation(b);
0126 
0127     // Progress groupbox & buttons
0128     progressButtons = new QButtonGroup(main_widget);
0129     box = new QGroupBox(QStringLiteral("Progress dialog mode"), main_widget);
0130     topLayout->addWidget(box, 10);
0131     connect(progressButtons, qOverload<QAbstractButton *>(&QButtonGroup::buttonClicked), this, &KioWorkerTest::changeProgressMode);
0132 
0133     hbLayout = new QHBoxLayout(box);
0134 
0135     rbProgressNone = new QRadioButton(QStringLiteral("None"), box);
0136     progressButtons->addButton(rbProgressNone);
0137     hbLayout->addWidget(rbProgressNone, 5);
0138 
0139     rbProgressDefault = new QRadioButton(QStringLiteral("Default"), box);
0140     progressButtons->addButton(rbProgressDefault);
0141     hbLayout->addWidget(rbProgressDefault, 5);
0142 
0143     rbProgressStatus = new QRadioButton(QStringLiteral("Status"), box);
0144     progressButtons->addButton(rbProgressStatus);
0145     hbLayout->addWidget(rbProgressStatus, 5);
0146 
0147     b = progressButtons->buttons()[pr];
0148     b->setChecked(true);
0149     changeProgressMode(b);
0150 
0151     // statusbar progress widget
0152     statusTracker = new KStatusBarJobTracker(statusBar());
0153 
0154     // run & stop buttons
0155     hbLayout = new QHBoxLayout();
0156     topLayout->addLayout(hbLayout);
0157     hbLayout->setParent(topLayout);
0158 
0159     pbStart = new QPushButton(QStringLiteral("&Start"), main_widget);
0160     pbStart->setFixedSize(pbStart->sizeHint());
0161     connect(pbStart, &QAbstractButton::clicked, this, &KioWorkerTest::startJob);
0162     hbLayout->addWidget(pbStart, 5);
0163 
0164     pbStop = new QPushButton(QStringLiteral("Sto&p"), main_widget);
0165     pbStop->setFixedSize(pbStop->sizeHint());
0166     pbStop->setEnabled(false);
0167     connect(pbStop, &QAbstractButton::clicked, this, &KioWorkerTest::stopJob);
0168     hbLayout->addWidget(pbStop, 5);
0169 
0170     // close button
0171     close = new QPushButton(QStringLiteral("&Close"), main_widget);
0172     close->setFixedSize(close->sizeHint());
0173     connect(close, &QAbstractButton::clicked, this, &KioWorkerTest::slotQuit);
0174 
0175     topLayout->addWidget(close, 5);
0176 
0177     main_widget->setMinimumSize(main_widget->sizeHint());
0178     setCentralWidget(main_widget);
0179 }
0180 
0181 void KioWorkerTest::slotQuit()
0182 {
0183     qApp->quit();
0184 }
0185 
0186 void KioWorkerTest::changeOperation(QAbstractButton *b)
0187 {
0188     // only two urls for copy and move
0189     bool enab = rbCopy->isChecked() || rbMove->isChecked();
0190 
0191     le_dest->setEnabled(enab);
0192 
0193     selectedOperation = opButtons->buttons().indexOf(b);
0194 }
0195 
0196 void KioWorkerTest::changeProgressMode(QAbstractButton *b)
0197 {
0198     progressMode = progressButtons->buttons().indexOf(b);
0199 
0200     if (progressMode == ProgressStatus) {
0201         statusBar()->show();
0202     } else {
0203         statusBar()->hide();
0204     }
0205 }
0206 
0207 void KioWorkerTest::startJob()
0208 {
0209     QUrl sCurrent(QUrl::fromLocalFile(QDir::currentPath()));
0210     QString sSrc(le_source->text());
0211     QUrl src = QUrl(sCurrent).resolved(QUrl(sSrc));
0212 
0213     if (!src.isValid()) {
0214         QMessageBox::critical(this, QStringLiteral("KioWorker Error Message"), QStringLiteral("Source URL is malformed"));
0215         return;
0216     }
0217 
0218     QString sDest(le_dest->text());
0219     QUrl dest = QUrl(sCurrent).resolved(QUrl(sDest));
0220 
0221     if (!dest.isValid() && (selectedOperation == Copy || selectedOperation == Move)) {
0222         QMessageBox::critical(this, QStringLiteral("KioWorker Error Message"), QStringLiteral("Destination URL is malformed"));
0223         return;
0224     }
0225 
0226     pbStart->setEnabled(false);
0227 
0228     KIO::JobFlags observe = DefaultFlags;
0229     if (progressMode != ProgressDefault) {
0230         observe = HideProgressInfo;
0231     }
0232 
0233     switch (selectedOperation) {
0234     case List: {
0235         KIO::ListJob *listJob = KIO::listDir(src);
0236         job = listJob;
0237         connect(listJob, &KIO::ListJob::entries, this, &KioWorkerTest::slotEntries);
0238         break;
0239     }
0240 
0241     case ListRecursive: {
0242         KIO::ListJob *listJob = KIO::listRecursive(src);
0243         job = listJob;
0244         connect(listJob, &KIO::ListJob::entries, this, &KioWorkerTest::slotEntries);
0245         break;
0246     }
0247 
0248     case Stat:
0249         job = KIO::statDetails(src, KIO::StatJob::SourceSide);
0250         break;
0251 
0252     case Get: {
0253         KIO::TransferJob *tjob = KIO::get(src, KIO::Reload);
0254         job = tjob;
0255         connect(tjob, &KIO::TransferJob::data, this, &KioWorkerTest::slotData);
0256         break;
0257     }
0258 
0259     case Put: {
0260         putBuffer = 0;
0261         KIO::TransferJob *tjob = KIO::put(src, -1, KIO::Overwrite);
0262         tjob->setTotalSize(48 * 1024 * 1024);
0263         job = tjob;
0264         connect(tjob, &TransferJob::dataReq, this, &KioWorkerTest::slotDataReq);
0265         break;
0266     }
0267 
0268     case Copy:
0269         job = KIO::copy(src, dest, observe);
0270         break;
0271 
0272     case Move:
0273         job = KIO::move(src, dest, observe);
0274         break;
0275 
0276     case Delete:
0277         job = KIO::del(src, observe);
0278         break;
0279 
0280     case Mkdir:
0281         job = KIO::mkdir(src);
0282         break;
0283 
0284     case Mimetype:
0285         job = KIO::mimetype(src);
0286         break;
0287     }
0288 
0289     statusBar()->addWidget(statusTracker->widget(job), 0);
0290 
0291     connect(job, &KJob::result, this, &KioWorkerTest::slotResult);
0292 
0293     if (progressMode == ProgressStatus) {
0294         statusTracker->registerJob(job);
0295     }
0296 
0297     pbStop->setEnabled(true);
0298 }
0299 
0300 void KioWorkerTest::slotResult(KJob *_job)
0301 {
0302     if (_job->error()) {
0303         _job->uiDelegate()->showErrorMessage();
0304     } else if (selectedOperation == Stat) {
0305         UDSEntry entry = static_cast<KIO::StatJob *>(_job)->statResult();
0306         printUDSEntry(entry);
0307     } else if (selectedOperation == Mimetype) {
0308         qDebug() << "MIME type is " << static_cast<KIO::MimetypeJob *>(_job)->mimetype();
0309     }
0310 
0311     if (job == _job) {
0312         job = nullptr;
0313     }
0314 
0315     pbStart->setEnabled(true);
0316     pbStop->setEnabled(false);
0317 
0318     // statusBar()->removeWidget( statusTracker->widget(job) );
0319 }
0320 
0321 void KioWorkerTest::printUDSEntry(const KIO::UDSEntry &entry)
0322 {
0323     // It's rather rare to iterate that way, usually you'd use numberValue/stringValue directly.
0324     // This is just to print out all that we got
0325 
0326     QDateTime timestamp;
0327 
0328     const QVector<uint> keys = entry.fields();
0329     for (auto it = keys.cbegin(); it != keys.cend(); ++it) {
0330         switch (*it) {
0331         case KIO::UDSEntry::UDS_FILE_TYPE: {
0332             mode_t mode = (mode_t)entry.numberValue(*it);
0333             qDebug() << "File Type : " << mode;
0334             if (Utils::isDirMask(mode)) {
0335                 qDebug() << "is a dir";
0336             }
0337             if (Utils::isLinkMask(mode)) {
0338                 qDebug() << "is a link";
0339             }
0340             break;
0341         }
0342         case KIO::UDSEntry::UDS_ACCESS:
0343             qDebug() << "Access permissions : " << (mode_t)(entry.numberValue(*it));
0344             break;
0345         case KIO::UDSEntry::UDS_USER:
0346             qDebug() << "User : " << (entry.stringValue(*it));
0347             break;
0348         case KIO::UDSEntry::UDS_GROUP:
0349             qDebug() << "Group : " << (entry.stringValue(*it));
0350             break;
0351         case KIO::UDSEntry::UDS_NAME:
0352             qDebug() << "Name : " << (entry.stringValue(*it));
0353             // m_strText = decodeFileName( it.value().toString() );
0354             break;
0355         case KIO::UDSEntry::UDS_URL:
0356             qDebug() << "URL : " << (entry.stringValue(*it));
0357             break;
0358         case KIO::UDSEntry::UDS_MIME_TYPE:
0359             qDebug() << "MimeType : " << (entry.stringValue(*it));
0360             break;
0361         case KIO::UDSEntry::UDS_LINK_DEST:
0362             qDebug() << "LinkDest : " << (entry.stringValue(*it));
0363             break;
0364         case KIO::UDSEntry::UDS_SIZE:
0365             qDebug() << "Size: " << KIO::convertSize(entry.numberValue(*it));
0366             break;
0367         case KIO::UDSEntry::UDS_CREATION_TIME:
0368             timestamp = QDateTime::fromSecsSinceEpoch(entry.numberValue(*it));
0369             qDebug() << "CreationTime: " << QLocale().toString(timestamp, QLocale::ShortFormat);
0370             break;
0371         case KIO::UDSEntry::UDS_MODIFICATION_TIME:
0372             timestamp = QDateTime::fromSecsSinceEpoch(entry.numberValue(*it));
0373             qDebug() << "ModificationTime: " << QLocale().toString(timestamp, QLocale::ShortFormat);
0374             break;
0375         case KIO::UDSEntry::UDS_ACCESS_TIME:
0376             timestamp = QDateTime::fromSecsSinceEpoch(entry.numberValue(*it));
0377             qDebug() << "AccessTime: " << QLocale().toString(timestamp, QLocale::ShortFormat);
0378             break;
0379         }
0380     }
0381 }
0382 
0383 void KioWorkerTest::slotEntries(KIO::Job *job, const KIO::UDSEntryList &list)
0384 {
0385     QUrl url = static_cast<KIO::ListJob *>(job)->url();
0386     KProtocolInfo::ExtraFieldList extraFields = KProtocolInfo::extraFields(url);
0387     UDSEntryList::ConstIterator it = list.begin();
0388     for (; it != list.end(); ++it) {
0389         // For each file...
0390         QString name = (*it).stringValue(KIO::UDSEntry::UDS_NAME);
0391         qDebug() << name;
0392 
0393         KProtocolInfo::ExtraFieldList::Iterator extraFieldsIt = extraFields.begin();
0394         const QVector<uint> fields = it->fields();
0395         QVector<uint>::ConstIterator it2 = fields.begin();
0396         for (; it2 != fields.end(); it2++) {
0397             if (*it2 >= UDSEntry::UDS_EXTRA && *it2 <= UDSEntry::UDS_EXTRA_END) {
0398                 if (extraFieldsIt != extraFields.end()) {
0399                     QString column = (*extraFieldsIt).name;
0400                     // QString type = (*extraFieldsIt).type;
0401                     qDebug() << "  Extra data (" << column << ") :" << it->stringValue(*it2);
0402                     ++extraFieldsIt;
0403                 } else {
0404                     qDebug() << "  Extra data (UNDEFINED) :" << it->stringValue(*it2);
0405                 }
0406             }
0407         }
0408     }
0409 }
0410 
0411 void KioWorkerTest::slotData(KIO::Job *, const QByteArray &data)
0412 {
0413     if (data.size() == 0) {
0414         qDebug() << "Data: <End>";
0415     } else {
0416         qDebug() << "Data: \"" << QString(data) << "\"";
0417     }
0418 }
0419 
0420 void KioWorkerTest::slotDataReq(KIO::Job *, QByteArray &data)
0421 {
0422     /* clang-format off */
0423     const char *fileDataArray[] = {
0424         "Hello world\n",
0425         "This is a test file\n",
0426         "You can safely delete it.\n",
0427         "BIG\n",
0428         "BIG1\n",
0429         "BIG2\n",
0430         "BIG3\n",
0431         "BIG4\n",
0432         "BIG5\n",
0433         nullptr
0434     };
0435     /* clang-format on */
0436 
0437     const char *fileData = fileDataArray[putBuffer++];
0438 
0439     if (!fileData) {
0440         qDebug() << "DataReq: <End>";
0441         return;
0442     }
0443     if (!strncmp(fileData, "BIG", 3)) {
0444         data.fill(0, 8 * 1024 * 1024);
0445     } else {
0446         data = QByteArray(fileData, strlen(fileData));
0447     }
0448     qDebug() << "DataReq: \"" << fileData << "\"";
0449     QThread::sleep(1); // want to see progress info...
0450 }
0451 
0452 void KioWorkerTest::stopJob()
0453 {
0454     qDebug() << "KioWorkerTest::stopJob()";
0455     job->kill();
0456     job = nullptr;
0457 
0458     pbStop->setEnabled(false);
0459     pbStart->setEnabled(true);
0460 }
0461 
0462 int main(int argc, char **argv)
0463 {
0464     const char version[] = "v0.0.0 0000"; // :-)
0465 
0466     QApplication app(argc, argv);
0467     app.setApplicationVersion(version);
0468 
0469     uint op = KioWorkerTest::Copy;
0470     uint pr = 0;
0471     QString src;
0472     QString dest;
0473     QString operation;
0474     {
0475         QCommandLineParser parser;
0476         parser.addVersionOption();
0477         parser.setApplicationDescription(QStringLiteral("Test for KIO workers"));
0478         parser.addHelpOption();
0479         parser.addOption(
0480             QCommandLineOption(QStringList() << QStringLiteral("s") << QStringLiteral("src"), QStringLiteral("Source URL"), QStringLiteral("url")));
0481         parser.addOption(
0482             QCommandLineOption(QStringList() << QStringLiteral("d") << QStringLiteral("dest"), QStringLiteral("Destination URL"), QStringLiteral("url")));
0483         parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("o") << QStringLiteral("operation"),
0484                                             QStringLiteral("Operation (list,listrecursive,stat,get,put,copy,move,del,mkdir)"),
0485                                             QStringLiteral("operation")));
0486         parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("p") << QStringLiteral("progress"),
0487                                             QStringLiteral("Progress Type (none,default,status)"),
0488                                             QStringLiteral("progress"),
0489                                             QStringLiteral("default")));
0490         parser.process(app);
0491 
0492         src = parser.value(QStringLiteral("src"));
0493         dest = parser.value(QStringLiteral("dest"));
0494 
0495         operation = parser.value(QStringLiteral("operation"));
0496         if (operation == QLatin1String("list")) {
0497             op = KioWorkerTest::List;
0498         } else if (operation == QLatin1String("listrecursive")) {
0499             op = KioWorkerTest::ListRecursive;
0500         } else if (operation == QLatin1String("stat")) {
0501             op = KioWorkerTest::Stat;
0502         } else if (operation == QLatin1String("get")) {
0503             op = KioWorkerTest::Get;
0504         } else if (operation == QLatin1String("put")) {
0505             op = KioWorkerTest::Put;
0506         } else if (operation == QLatin1String("copy")) {
0507             op = KioWorkerTest::Copy;
0508         } else if (operation == QLatin1String("move")) {
0509             op = KioWorkerTest::Move;
0510         } else if (operation == QLatin1String("del")) {
0511             op = KioWorkerTest::Delete;
0512         } else if (operation == QLatin1String("mkdir")) {
0513             op = KioWorkerTest::Mkdir;
0514         } else if (!operation.isEmpty()) {
0515             qWarning("Unknown operation, see --help");
0516             return 1;
0517         }
0518 
0519         QString progress = parser.value(QStringLiteral("progress"));
0520         if (progress == QLatin1String("none")) {
0521             pr = KioWorkerTest::ProgressNone;
0522         } else if (progress == QLatin1String("default")) {
0523             pr = KioWorkerTest::ProgressDefault;
0524         } else if (progress == QLatin1String("status")) {
0525             pr = KioWorkerTest::ProgressStatus;
0526         } else {
0527             qWarning("Unknown progress mode, see --help");
0528             return 1;
0529         }
0530     }
0531 
0532     KioWorkerTest *test = new KioWorkerTest(src, dest, op, pr);
0533     if (!operation.isEmpty()) {
0534         QTimer::singleShot(100, test, SLOT(startJob()));
0535     }
0536     test->show();
0537     test->resize(test->sizeHint());
0538 
0539     app.exec();
0540 }
0541 
0542 #include "moc_kioworkertest.cpp"