File indexing completed on 2024-12-01 03:41:22

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     : QMainWindow(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, &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, &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::stat(src);
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 QList<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_LOCAL_USER_ID:
0352             qDebug() << "User id : " << (entry.numberValue(*it));
0353             break;
0354         case KIO::UDSEntry::UDS_LOCAL_GROUP_ID:
0355             qDebug() << "Group id : " << (entry.numberValue(*it));
0356             break;
0357         case KIO::UDSEntry::UDS_NAME:
0358             qDebug() << "Name : " << (entry.stringValue(*it));
0359             // m_strText = decodeFileName( it.value().toString() );
0360             break;
0361         case KIO::UDSEntry::UDS_URL:
0362             qDebug() << "URL : " << (entry.stringValue(*it));
0363             break;
0364         case KIO::UDSEntry::UDS_MIME_TYPE:
0365             qDebug() << "MimeType : " << (entry.stringValue(*it));
0366             break;
0367         case KIO::UDSEntry::UDS_LINK_DEST:
0368             qDebug() << "LinkDest : " << (entry.stringValue(*it));
0369             break;
0370         case KIO::UDSEntry::UDS_SIZE:
0371             qDebug() << "Size: " << KIO::convertSize(entry.numberValue(*it));
0372             break;
0373         case KIO::UDSEntry::UDS_CREATION_TIME:
0374             timestamp = QDateTime::fromSecsSinceEpoch(entry.numberValue(*it));
0375             qDebug() << "CreationTime: " << QLocale().toString(timestamp, QLocale::ShortFormat);
0376             break;
0377         case KIO::UDSEntry::UDS_MODIFICATION_TIME:
0378             timestamp = QDateTime::fromSecsSinceEpoch(entry.numberValue(*it));
0379             qDebug() << "ModificationTime: " << QLocale().toString(timestamp, QLocale::ShortFormat);
0380             break;
0381         case KIO::UDSEntry::UDS_ACCESS_TIME:
0382             timestamp = QDateTime::fromSecsSinceEpoch(entry.numberValue(*it));
0383             qDebug() << "AccessTime: " << QLocale().toString(timestamp, QLocale::ShortFormat);
0384             break;
0385         }
0386     }
0387 }
0388 
0389 void KioWorkerTest::slotEntries(KIO::Job *job, const KIO::UDSEntryList &list)
0390 {
0391     QUrl url = static_cast<KIO::ListJob *>(job)->url();
0392     KProtocolInfo::ExtraFieldList extraFields = KProtocolInfo::extraFields(url);
0393     UDSEntryList::ConstIterator it = list.begin();
0394     for (; it != list.end(); ++it) {
0395         // For each file...
0396         QString name = (*it).stringValue(KIO::UDSEntry::UDS_NAME);
0397         qDebug() << name;
0398 
0399         KProtocolInfo::ExtraFieldList::Iterator extraFieldsIt = extraFields.begin();
0400         const QList<uint> fields = it->fields();
0401         QList<uint>::ConstIterator it2 = fields.begin();
0402         for (; it2 != fields.end(); it2++) {
0403             if (*it2 >= UDSEntry::UDS_EXTRA && *it2 <= UDSEntry::UDS_EXTRA_END) {
0404                 if (extraFieldsIt != extraFields.end()) {
0405                     QString column = (*extraFieldsIt).name;
0406                     // QString type = (*extraFieldsIt).type;
0407                     qDebug() << "  Extra data (" << column << ") :" << it->stringValue(*it2);
0408                     ++extraFieldsIt;
0409                 } else {
0410                     qDebug() << "  Extra data (UNDEFINED) :" << it->stringValue(*it2);
0411                 }
0412             }
0413         }
0414     }
0415 }
0416 
0417 void KioWorkerTest::slotData(KIO::Job *, const QByteArray &data)
0418 {
0419     if (data.size() == 0) {
0420         qDebug() << "Data: <End>";
0421     } else {
0422         qDebug() << "Data: \"" << QString::fromUtf8(data) << "\"";
0423     }
0424 }
0425 
0426 void KioWorkerTest::slotDataReq(KIO::Job *, QByteArray &data)
0427 {
0428     /* clang-format off */
0429     const char *fileDataArray[] = {
0430         "Hello world\n",
0431         "This is a test file\n",
0432         "You can safely delete it.\n",
0433         "BIG\n",
0434         "BIG1\n",
0435         "BIG2\n",
0436         "BIG3\n",
0437         "BIG4\n",
0438         "BIG5\n",
0439         nullptr
0440     };
0441     /* clang-format on */
0442 
0443     const char *fileData = fileDataArray[putBuffer++];
0444 
0445     if (!fileData) {
0446         qDebug() << "DataReq: <End>";
0447         return;
0448     }
0449     if (!strncmp(fileData, "BIG", 3)) {
0450         data.fill(0, 8 * 1024 * 1024);
0451     } else {
0452         data = QByteArray(fileData, strlen(fileData));
0453     }
0454     qDebug() << "DataReq: \"" << fileData << "\"";
0455     QThread::sleep(1); // want to see progress info...
0456 }
0457 
0458 void KioWorkerTest::stopJob()
0459 {
0460     qDebug() << "KioWorkerTest::stopJob()";
0461     job->kill();
0462     job = nullptr;
0463 
0464     pbStop->setEnabled(false);
0465     pbStart->setEnabled(true);
0466 }
0467 
0468 int main(int argc, char **argv)
0469 {
0470     const char version[] = "v0.0.0 0000"; // :-)
0471 
0472     QApplication app(argc, argv);
0473     app.setApplicationVersion(QString::fromLatin1(version));
0474 
0475     uint op = KioWorkerTest::Copy;
0476     uint pr = 0;
0477     QString src;
0478     QString dest;
0479     QString operation;
0480     {
0481         QCommandLineParser parser;
0482         parser.addVersionOption();
0483         parser.setApplicationDescription(QStringLiteral("Test for KIO workers"));
0484         parser.addHelpOption();
0485         parser.addOption(
0486             QCommandLineOption(QStringList() << QStringLiteral("s") << QStringLiteral("src"), QStringLiteral("Source URL"), QStringLiteral("url")));
0487         parser.addOption(
0488             QCommandLineOption(QStringList() << QStringLiteral("d") << QStringLiteral("dest"), QStringLiteral("Destination URL"), QStringLiteral("url")));
0489         parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("o") << QStringLiteral("operation"),
0490                                             QStringLiteral("Operation (list,listrecursive,stat,get,put,copy,move,del,mkdir)"),
0491                                             QStringLiteral("operation")));
0492         parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("p") << QStringLiteral("progress"),
0493                                             QStringLiteral("Progress Type (none,default,status)"),
0494                                             QStringLiteral("progress"),
0495                                             QStringLiteral("default")));
0496         parser.process(app);
0497 
0498         src = parser.value(QStringLiteral("src"));
0499         dest = parser.value(QStringLiteral("dest"));
0500 
0501         operation = parser.value(QStringLiteral("operation"));
0502         if (operation == QLatin1String("list")) {
0503             op = KioWorkerTest::List;
0504         } else if (operation == QLatin1String("listrecursive")) {
0505             op = KioWorkerTest::ListRecursive;
0506         } else if (operation == QLatin1String("stat")) {
0507             op = KioWorkerTest::Stat;
0508         } else if (operation == QLatin1String("get")) {
0509             op = KioWorkerTest::Get;
0510         } else if (operation == QLatin1String("put")) {
0511             op = KioWorkerTest::Put;
0512         } else if (operation == QLatin1String("copy")) {
0513             op = KioWorkerTest::Copy;
0514         } else if (operation == QLatin1String("move")) {
0515             op = KioWorkerTest::Move;
0516         } else if (operation == QLatin1String("del")) {
0517             op = KioWorkerTest::Delete;
0518         } else if (operation == QLatin1String("mkdir")) {
0519             op = KioWorkerTest::Mkdir;
0520         } else if (!operation.isEmpty()) {
0521             qWarning("Unknown operation, see --help");
0522             return 1;
0523         }
0524 
0525         QString progress = parser.value(QStringLiteral("progress"));
0526         if (progress == QLatin1String("none")) {
0527             pr = KioWorkerTest::ProgressNone;
0528         } else if (progress == QLatin1String("default")) {
0529             pr = KioWorkerTest::ProgressDefault;
0530         } else if (progress == QLatin1String("status")) {
0531             pr = KioWorkerTest::ProgressStatus;
0532         } else {
0533             qWarning("Unknown progress mode, see --help");
0534             return 1;
0535         }
0536     }
0537 
0538     KioWorkerTest *test = new KioWorkerTest(src, dest, op, pr);
0539     if (!operation.isEmpty()) {
0540         QTimer::singleShot(100, test, SLOT(startJob()));
0541     }
0542     test->show();
0543     test->resize(test->sizeHint());
0544 
0545     return app.exec();
0546 }
0547 
0548 #include "moc_kioworkertest.cpp"