2018年4月8日日曜日

macOS ファイルオープンイベント

Finder でアプリケーションアイコンにファイルをドロップするとアプリケーションが起動されてファイルを開くプログラムです。PNG と XPM をドロップでき、アプリケーションウィンドウにも画像ファイルをドロップできるようにしています。

application.h:

#pragma once

#include <QApplication>

class Application : public QApplication
{
    Q_OBJECT

public:
    Application(int& argc, char** argv);

signals:
    void requestedFile(const QString& fileName);

protected:
    bool event(QEvent* event) override;
};
QApplication をサブクラス化し event() を再実装して QEvent::FileOpen イベントを受け取れるようにします。
application.cpp:

#include "application.h"
#include <QFileOpenEvent>

Application::Application(int& argc, char** argv)
    : QApplication(argc, argv)
{
}

bool Application::event(QEvent* event)
{
    if (event->type() == QEvent::FileOpen) {
        emit requestedFile(static_cast<QFileOpenEvent*>(event)->file());
        return true;
    }

    return QApplication::event(event);
}
QEvent::FileOpen イベントを受け取ったならば、QFileOpenEvent::file() でファイル名が分かります。 そのファイル名を実引数にして requestedFile() シグナルを送信します。
droparea.h:

#pragma once

#include <QWidget>

class QDragEnterEvent;
class QDropEvent;

class DropArea : public QWidget
{
    Q_OBJECT

public:
    explicit DropArea(QWidget* parent = 0);

public slots:
    void appendImage(const QString& fileName);

protected:
    void dragEnterEvent(QDragEnterEvent* event) override;
    void dropEvent(QDropEvent* event) override;

public:
    QSize sizeHint() const override;

private:
    QSize totalImageSize;
    int numberOfImages;
};
アプリケーションアイコンにドロップした画像ファイルを表示するウィジェットです。このウィジェットに画像ファイルをドロップできるようにもしています。
droparea.cpp:

#include "droparea.h"
#include "application.h"
#include "pixmapview.h"
#include <QApplication>
#include <QDragEnterEvent>
#include <QMimeData>
#include <QLabel>
#include <QLayout>

DropArea::DropArea(QWidget* parent)
    : QWidget(parent)
{
    numberOfImages = 0;

    setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);

    setAcceptDrops(true);

    const auto topLayout = new QVBoxLayout(this);
    topLayout->addStretch();
    topLayout->setSpacing(8);

    QObject::connect(qobject_cast<Application*>(qApp), &Application::requestedFile, this, &DropArea::appendImage);

    setAutoFillBackground(true);
    QPalette background = palette();
    background.setColor(QPalette::Window, Qt::white);
    setPalette(background);
}

void DropArea::appendImage(const QString& fileName)
{
    const QPixmap pixmap(fileName);
    if (!pixmap.isNull()) {
        auto pixmapView = new PixmapView(pixmap, fileName);

        numberOfImages += 1;
        totalImageSize.rwidth() = qMax(totalImageSize.width(), pixmapView->width());
        totalImageSize.rheight() += pixmapView->height();

        auto topLayout = qobject_cast<QVBoxLayout*>(layout());
        Q_ASSERT(topLayout);

        int left, top, right, bottom;
        topLayout->getContentsMargins(&left, &top, &right, &bottom);
        const int newWidth = totalImageSize.width() + left + right;
        const int newHeight = qMax(totalImageSize.height() + top + bottom + topLayout->spacing()*(numberOfImages - 1), height());
        setFixedSize(newWidth, newHeight);

        topLayout->insertWidget(topLayout->count() - 1, pixmapView);
    }
}

void DropArea::dragEnterEvent(QDragEnterEvent* event)
{
    if (event->mimeData()->hasUrls()) {
        event->accept();
    }
}

void DropArea::dropEvent(QDropEvent* event)
{
    for (const auto& url : event->mimeData()->urls()) {
        appendImage(url.path());
    }
    event->acceptProposedAction();
}

QSize DropArea::sizeHint() const
{
    return QSize(300, 300);
}
Application::requestedFile() シグナルを appendImage() スロットに接続して、アプリケーションアイコンにファイルがドロップされたときに画像追加がされるようにしています。

ドロップされたファイルで QPixmap のインスタンス生成が成功したならば画像ファイルと考えます。失敗したならば何もしません。画像ファイルがドロップされたときにレイアウトの最後のスペーサーの前に画像を表示する PixmapView インスタンスを追加しています。レイアウトの最後のスペーサーは addStretch() で追加しているのでできる限り広がるため画像が上部に詰められてレイアウトされます。
pixmapview.h:

#pragma once

#include <QWidget>

class PixmapView : public QWidget
{
    Q_OBJECT

public:
    PixmapView(const QPixmap& pixmap, const QString& path, QWidget* parent = 0);
};
画像ファイル一つを表示するウィジェットです。
pixmapview.cpp:

#include "pixmapview.h"
#include <QLabel>
#include <QLayout>
#include <QDebug>

PixmapView::PixmapView(const QPixmap& pixmap, const QString& path, QWidget* parent)
    : QWidget(parent)
{
    const auto topLayout = new QVBoxLayout(this);

    const auto pixmapLabel = new QLabel;
    pixmapLabel->setPixmap(pixmap);
    topLayout->addWidget(pixmapLabel);

    topLayout->addWidget(new QLabel(path));
    setFixedSize(sizeHint());

    setAutoFillBackground(true);
    QPalette background = palette();
    background.setColor(QPalette::Window, "whitesmoke");
    setPalette(background);
}
画像の下にドロップされた画像のファイル名も表示しています。
harness.h:

#pragma once

#include <QWidget>

class Harness : public QWidget
{
    Q_OBJECT

public:
    explicit Harness(QWidget* parent = 0);
};
画像を表示する DropArea をスクロールさせて表示するウィジェットです。
harness.cpp:

#include "harness.h"
#include "droparea.h"
#include <QScrollArea>
#include <QLayout>

Harness::Harness(QWidget* parent)
    : QWidget(parent)
{
    const auto topLayout = new QVBoxLayout(this);

    const auto dropArea = new DropArea(this);

    const auto scrollArea = new QScrollArea(this);
    scrollArea->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
    scrollArea->resize(300, 300);
    scrollArea->setWidget(dropArea);

    topLayout->addWidget(scrollArea);
}
スクロール領域がウィンドウ全体を占めるようにしています。
main.cpp:

#include "application.h"
#include "harness.h"

int main(int argc, char** argv)
{
    Application app(argc, argv);

    Harness harness;
    harness.show();

    return app.exec();
}
main() では Harness のインスタンスを作って表示しているだけです。
Info.plist

<!DOCTYPE plist PUBLIC
    "-//Apple Computer//DTD PLIST 1.0//EN"
    "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>CFBundleDocumentTypes</key>
    <array>
        <dict>
            <key>CFBundleTypeExtensions</key>
            <array>
                <string>xpm</string>
            </array>
            <key>CFBundleTypeMIMETypes</key>
            <array>
                <string>image/x-xpm</string>
            </array>
            <key>CFBundleTypeName</key>
            <string>X PixMap File</string>
            <key>CFBundleTypeRole</key>
            <string>Viewer</string>
            <key>LSIsAppleDefaultForType</key>
            <true/>
        </dict>
        <dict>
            <key>CFBundleTypeExtensions</key>
            <array>
                <string>png</string>
            </array>
            <key>CFBundleTypeMIMETypes</key>
            <array>
                <string>image/png</string>
            </array>
            <key>CFBundleTypeName</key>
            <string>Portable Network Graphics File</string>
            <key>CFBundleTypeRole</key>
            <string>Viewer</string>
            <key>LSIsAppleDefaultForType</key>
            <true/>
        </dict>
    </array>
    <key>CFBundleIconFile</key>
    <string>appfileopen.icns</string>
    <key>CFBundleExecutable</key>
    <string>appleevents</string>
    <key>CFBundleIdentifier</key>
    <string>jp.co.reversedomainname.fileopenevent</string>
    <key>CFBundleInfoDictionaryVersion</key>
    <string>6.0</string>
    <key>CFBundlePackageType</key>
    <string>APPL</string>
    <key>CFBundleExecutable</key>
    <string>AppFileOpen</string>
    <key>CFBundleSignature</key>
    <string>????</string>
    <key>CFBundleVersion</key>
    <string>1.0</string>
    <key>CSResourcesFileMapped</key>
    <true/>
    <key>NSPrincipalClass</key>
    <string>NSApplication</string>
    <key>NSHighResolutionCapable</key>
    <string>True</string>
</dict>
</plist>
PNG と XPM をドロップするとアプリケーションが起動されるように設定しています。アプリケーションアイコン appfileopen.icns も設定しています。
appfileopen.pro:

!macos {
    error(Only for macOS)
}

QT += widgets

TARGET = AppFileOpen

TEMPLATE = app
SOURCES += main.cpp \
    pixmapview.cpp \
    application.cpp \
    droparea.cpp \
    harness.cpp

HEADERS += \
    pixmapview.h \
    application.h \
    droparea.h \
    harness.h

QMAKE_INFO_PLIST=Info.plist
ICON=icon/appfileopen.icns
QMAKE_INFO_PLIST に Info.plist を指定し、ICON に appfileopen.icns を指定して、ビルドするとアプリケーションバンドルの適切な場所にコピーされるようにしています。



左上のアプリケーションアイコンに PNG か XPM をドロップするとアプリケーションが起動し画像ファイルが表示されます。起動後にドロップすると画像ファイルが追加されます。


アプリケーションウィンドウに画像ファイルをドロップすると画像ファイルが追加して表示されます。Qt が扱える画像はすべて受け付けるようにしています。画像ファイル以外もドロップできますが無視して何もしません。

参考情報

QFileOpenEvent Class

for ベンチマーク

QStringList の for と foreach、range for でのベンチマークです。
forbench.cpp:

#include 
#include 

class ForBenchmark : public QObject
{
    Q_OBJECT

public:
    ForBenchmark() : sizeOfList(1000) {}

    enum class IterationType {
        IndexAt,
        IndexValue,
        IndexMutable,
        Java,
        JavaMutable,
        Stl,
        StlConst,
        Qtforeach,
        QtForeachConst,
        QtForeachConstRef,
#if __cplusplus >= 201103L || (_MSC_VER >= 1700)
        RangeFor,
        RangeForConst,
        RangeForConstRef,
        RangeForAuto,
        RangeForConstAuto,
        RangeForConstAutoRef,
        RangeForAutoRvalue,
        AutoIterator,
        AutoConstIterator,
#endif
    };

private slots:
    void forBenchmark();
    void forBenchmark_data();

private:
    QStringList list;
    const int sizeOfList;
};

Q_DECLARE_METATYPE(ForBenchmark::IterationType)

void ForBenchmark::forBenchmark_data()
{
    QTest::addColumn("type");

    QTest::newRow("Index At") << IterationType::IndexAt;
    QTest::newRow("Index Value") << IterationType::IndexValue;
    QTest::newRow("Index Mutable") << IterationType::IndexMutable;
    QTest::newRow("Java mutable iterator") << IterationType::JavaMutable;
    QTest::newRow("Java iterator") << IterationType::Java;
    QTest::newRow("STL iterator") << IterationType::Stl;
    QTest::newRow("STL const iterator") << IterationType::StlConst;
    QTest::newRow("Qt foreach") << IterationType::Qtforeach;
    QTest::newRow("Qt foreach, const") << IterationType::QtForeachConst;
    QTest::newRow("Qt foreach, const&") << IterationType::QtForeachConstRef;
#if __cplusplus >= 201103L || (_MSC_VER >= 1700)
    QTest::newRow("Range for") << IterationType::RangeFor;
    QTest::newRow("Range for, const") << IterationType::RangeForConst;
    QTest::newRow("Range for, const&") << IterationType::RangeForConstRef;
    QTest::newRow("Range for, auto") << IterationType::RangeForAuto;
    QTest::newRow("Range for, const auto") << IterationType::RangeForConstAuto;
    QTest::newRow("Range for, const auto&") << IterationType::RangeForConstAutoRef;
    QTest::newRow("Range for, auto&&") <<  IterationType::RangeForAutoRvalue;
    QTest::newRow("auto iterator") << IterationType::AutoIterator;
    QTest::newRow("auto const iterator") << IterationType::AutoConstIterator;
#endif

    for (int n = 0; n < sizeOfList; n++) {
        list << QString::number(n);
    }
}

void ForBenchmark::forBenchmark()
{
    QFETCH(IterationType, type);

    int sum = 0;

    switch (type) {
    case IterationType::IndexAt:
        QBENCHMARK {
            for (int i = 0; i < sizeOfList; ++i) {
                sum += list.at(i).size();
            }
        }
        break;
    case IterationType::IndexValue:
        QBENCHMARK {
            for (int i = 0; i < sizeOfList; ++i) {
                sum += list.value(i).size();
            }
        }
        break;
    case IterationType::IndexMutable:
        QBENCHMARK {
            for (int i = 0; i < sizeOfList; ++i) {
                sum += list[i].size();
            }
        }
        break;
    case IterationType::Java: {
        QBENCHMARK {
            QStringListIterator it(list);
            while (it.hasNext())
                sum += it.next().size();
        }
        break;
    }
    case IterationType::JavaMutable: {
        QBENCHMARK {
            QMutableStringListIterator it(list);
            while (it.hasNext())
                sum += it.next().size();
        }
        break;
    }
    case IterationType::Stl: {
        QBENCHMARK {
            const QStringList::iterator end = list.end();
            for (QStringList::iterator it = list.begin(); it != end; ++it) {
                sum += (*it).size();
            }
        }
        break;
    }
    case IterationType::StlConst: {
        QBENCHMARK {
            const QStringList::const_iterator end = list.constEnd();
            for (QStringList::const_iterator it = list.constBegin(); it != end; ++it) {
                sum += (*it).size();
            }
        }
        break;
    }
    case IterationType::Qtforeach:
        QBENCHMARK {
            foreach (QString string, list) {
                sum += string.size();
            }
        }
        break;
    case IterationType::QtForeachConst:
        QBENCHMARK {
            foreach (const QString string, list) {
                sum += string.size();
            }
        }
        break;
    case IterationType::QtForeachConstRef:
        QBENCHMARK {
            foreach (const QString& string, list) {
                sum += string.size();
            }
        }
        break;
#if __cplusplus >= 201103L || (_MSC_VER >= 1700)
    case IterationType::RangeFor:
        QBENCHMARK {
            for (QString string : list) {
                sum += string.size();
            }
        }
        break;
    case IterationType::RangeForConst:
        QBENCHMARK {
            for (const QString string : list) {
                sum += string.size();
            }
        }
        break;
    case IterationType::RangeForConstRef:
        QBENCHMARK {
            for (const QString& string : list) {
                sum += string.size();
            }
        }
        break;
    case IterationType::RangeForAuto:
        QBENCHMARK {
            for (auto string : list) {
                sum += string.size();
            }
        }
        break;
    case IterationType::RangeForConstAuto:
        QBENCHMARK {
            for (const auto string : list) {
                sum += string.size();
            }
        }
        break;
    case IterationType::RangeForConstAutoRef:
        QBENCHMARK {
            for (const auto& string : list) {
                sum += string.size();
            }
        }
        break;
    case IterationType::RangeForAutoRvalue:
        QBENCHMARK {
            for (auto&& it : list) {
                sum += it.size();
            }
        }

        break;
    case IterationType::AutoIterator:
        QBENCHMARK {
            auto end = list.end();
            for (auto it = list.begin(); it != end; ++it) {
                sum += (*it).size();
            }
        }
        break;
    case IterationType::AutoConstIterator: {
        QBENCHMARK {
            auto end = list.constEnd();
            for (auto it = list.constBegin(); it != end; ++it) {
                sum += (*it).size();
            }
        }
    }
        break;
#endif
    }
}

QTEST_MAIN(ForBenchmark)

#include "forbench.moc"
forbench.pro:

QT+=testlib
QT -= gui
CONFIG += release
CONFIG -= app_bundle

TEMPLATE = app
TARGET = forbench

DEPENDPATH += .
INCLUDEPATH += .

SOURCES += forbench.cpp
macOS での実行結果です。
$ ./forbench
********* Start testing of ForBenchmark *********
Config: Using QtTest library 5.10.1, Qt 5.10.1 (x86_64-little_endian-lp64 shared (dynamic) release build; by Clang 8.1.0 (clang-802.0.42) (Apple))
PASS   : ForBenchmark::initTestCase()
PASS   : ForBenchmark::forBenchmark(Index At)
RESULT : ForBenchmark::forBenchmark():"Index At":
     0.000041 msecs per iteration (total: 87, iterations: 2097152)
PASS   : ForBenchmark::forBenchmark(Index Value)
RESULT : ForBenchmark::forBenchmark():"Index Value":
     0.013 msecs per iteration (total: 54, iterations: 4096)
PASS   : ForBenchmark::forBenchmark(Index Mutable)
RESULT : ForBenchmark::forBenchmark():"Index Mutable":
     0.00049 msecs per iteration (total: 65, iterations: 131072)
PASS   : ForBenchmark::forBenchmark(Java mutable iterator)
RESULT : ForBenchmark::forBenchmark():"Java mutable iterator":
     0.0131 msecs per iteration (total: 431, iterations: 32768)
PASS   : ForBenchmark::forBenchmark(Java iterator)
RESULT : ForBenchmark::forBenchmark():"Java iterator":
     0.0131 msecs per iteration (total: 215, iterations: 16384)
PASS   : ForBenchmark::forBenchmark(STL iterator)
RESULT : ForBenchmark::forBenchmark():"STL iterator":
     0.0132 msecs per iteration (total: 217, iterations: 16384)
PASS   : ForBenchmark::forBenchmark(STL const iterator)
RESULT : ForBenchmark::forBenchmark():"STL const iterator":
     0.0130 msecs per iteration (total: 107, iterations: 8192)
PASS   : ForBenchmark::forBenchmark(Qt foreach)
RESULT : ForBenchmark::forBenchmark():"Qt foreach":
     0.012 msecs per iteration (total: 53, iterations: 4096)
PASS   : ForBenchmark::forBenchmark(Qt foreach, const)
RESULT : ForBenchmark::forBenchmark():"Qt foreach, const":
     0.012 msecs per iteration (total: 53, iterations: 4096)
PASS   : ForBenchmark::forBenchmark(Qt foreach, const&)
RESULT : ForBenchmark::forBenchmark():"Qt foreach, const&":
     0.000046 msecs per iteration (total: 97, iterations: 2097152)
PASS   : ForBenchmark::forBenchmark(Range for)
RESULT : ForBenchmark::forBenchmark():"Range for":
     0.012 msecs per iteration (total: 51, iterations: 4096)
PASS   : ForBenchmark::forBenchmark(Range for, const)
RESULT : ForBenchmark::forBenchmark():"Range for, const":
     0.012 msecs per iteration (total: 51, iterations: 4096)
PASS   : ForBenchmark::forBenchmark(Range for, const&)
RESULT : ForBenchmark::forBenchmark():"Range for, const&":
     0.000042 msecs per iteration (total: 90, iterations: 2097152)
PASS   : ForBenchmark::forBenchmark(Range for, auto)
RESULT : ForBenchmark::forBenchmark():"Range for, auto":
     0.012 msecs per iteration (total: 52, iterations: 4096)
PASS   : ForBenchmark::forBenchmark(Range for, const auto)
RESULT : ForBenchmark::forBenchmark():"Range for, const auto":
     0.012 msecs per iteration (total: 52, iterations: 4096)
PASS   : ForBenchmark::forBenchmark(Range for, const auto&)
RESULT : ForBenchmark::forBenchmark():"Range for, const auto&":
     0.000042 msecs per iteration (total: 89, iterations: 2097152)
PASS   : ForBenchmark::forBenchmark(Range for, auto&&)
RESULT : ForBenchmark::forBenchmark():"Range for, auto&&":
     0.000042 msecs per iteration (total: 90, iterations: 2097152)
PASS   : ForBenchmark::forBenchmark(auto iterator)
RESULT : ForBenchmark::forBenchmark():"auto iterator":
     0.000041 msecs per iteration (total: 87, iterations: 2097152)
PASS   : ForBenchmark::forBenchmark(auto const iterator)
RESULT : ForBenchmark::forBenchmark():"auto const iterator":
     0.000041 msecs per iteration (total: 88, iterations: 2097152)
PASS   : ForBenchmark::cleanupTestCase()
Totals: 21 passed, 0 failed, 0 skipped, 0 blacklisted, 6451ms
********* Finished testing of ForBenchmark *********
$
Ubuntu での実行結果です。
$ ./forbench 
********* Start testing of ForBenchmark *********
Config: Using QtTest library 5.11.0, Qt 5.11.0 (x86_64-little_endian-lp64 shared (dynamic) release build; by GCC 5.3.1 20160406 (Red Hat 5.3.1-6))
PASS   : ForBenchmark::initTestCase()
PASS   : ForBenchmark::forBenchmark(Index At)
RESULT : ForBenchmark::forBenchmark():"Index At":
     0.0000026 msecs per iteration (total: 88, iterations: 33554432)
PASS   : ForBenchmark::forBenchmark(Index Value)
RESULT : ForBenchmark::forBenchmark():"Index Value":
     0.012 msecs per iteration (total: 53, iterations: 4096)
PASS   : ForBenchmark::forBenchmark(Index Mutable)
RESULT : ForBenchmark::forBenchmark():"Index Mutable":
     0.00073 msecs per iteration (total: 96, iterations: 131072)
PASS   : ForBenchmark::forBenchmark(Java mutable iterator)
RESULT : ForBenchmark::forBenchmark():"Java mutable iterator":
     0.0000033 msecs per iteration (total: 56, iterations: 16777216)
PASS   : ForBenchmark::forBenchmark(Java iterator)
RESULT : ForBenchmark::forBenchmark():"Java iterator":
     0.000016 msecs per iteration (total: 68, iterations: 4194304)
PASS   : ForBenchmark::forBenchmark(STL iterator)
RESULT : ForBenchmark::forBenchmark():"STL iterator":
     0.0000033 msecs per iteration (total: 56, iterations: 16777216)
PASS   : ForBenchmark::forBenchmark(STL const iterator)
RESULT : ForBenchmark::forBenchmark():"STL const iterator":
     0.0000028 msecs per iteration (total: 97, iterations: 33554432)
PASS   : ForBenchmark::forBenchmark(Qt foreach)
RESULT : ForBenchmark::forBenchmark():"Qt foreach":
     0.012 msecs per iteration (total: 52, iterations: 4096)
PASS   : ForBenchmark::forBenchmark(Qt foreach, const)
RESULT : ForBenchmark::forBenchmark():"Qt foreach, const":
     0.012 msecs per iteration (total: 53, iterations: 4096)
PASS   : ForBenchmark::forBenchmark(Qt foreach, const&)
RESULT : ForBenchmark::forBenchmark():"Qt foreach, const&":
     0.000015 msecs per iteration (total: 67, iterations: 4194304)
PASS   : ForBenchmark::forBenchmark(Range for)
RESULT : ForBenchmark::forBenchmark():"Range for":
     0.012 msecs per iteration (total: 52, iterations: 4096)
PASS   : ForBenchmark::forBenchmark(Range for, const)
RESULT : ForBenchmark::forBenchmark():"Range for, const":
     0.012 msecs per iteration (total: 52, iterations: 4096)
PASS   : ForBenchmark::forBenchmark(Range for, const&)
RESULT : ForBenchmark::forBenchmark():"Range for, const&":
     0.0000033 msecs per iteration (total: 57, iterations: 16777216)
PASS   : ForBenchmark::forBenchmark(Range for, auto)
RESULT : ForBenchmark::forBenchmark():"Range for, auto":
     0.013 msecs per iteration (total: 54, iterations: 4096)
PASS   : ForBenchmark::forBenchmark(Range for, const auto)
RESULT : ForBenchmark::forBenchmark():"Range for, const auto":
     0.012 msecs per iteration (total: 52, iterations: 4096)
PASS   : ForBenchmark::forBenchmark(Range for, const auto&)
RESULT : ForBenchmark::forBenchmark():"Range for, const auto&":
     0.0000035 msecs per iteration (total: 60, iterations: 16777216)
PASS   : ForBenchmark::forBenchmark(Range for, auto&&)
RESULT : ForBenchmark::forBenchmark():"Range for, auto&&":
     0.0000038 msecs per iteration (total: 64, iterations: 16777216)
PASS   : ForBenchmark::forBenchmark(auto iterator)
RESULT : ForBenchmark::forBenchmark():"auto iterator":
     0.0000041 msecs per iteration (total: 69, iterations: 16777216)
PASS   : ForBenchmark::forBenchmark(auto const iterator)
RESULT : ForBenchmark::forBenchmark():"auto const iterator":
     0.0000026 msecs per iteration (total: 89, iterations: 33554432)
PASS   : ForBenchmark::cleanupTestCase()
Totals: 21 passed, 0 failed, 0 skipped, 0 blacklisted, 5033ms
********* Finished testing of ForBenchmark *********
$


参考情報

Writing a Benchmark

名前付き色名

R、G、B を 16 進数一文字とするとき QColor と QML の color で扱える名前付き色名は以下のようになります。
  1. #RGB
  2. #RRGGBB
  3. #AARRGGBB
  4. #RRRGGGBBB
  5. #RRRRGGGGBBBB
  6. SVG 色名と transparent
4 と 5 の場合には各色要素の前 2 文字のみが参照され残りの文字は無視されるだけで色精度が上がる訳ではありません。以下のように記述してもエラーにはならず正しく色が使えます。
QColor("#7F_7F_7F_")
QColor("#80_80_80_")
QColor("#7F__7F__7F__")
QColor("#80__80__80__")

color: "#ff__00__00__" 
つまり、上の記述は下の記述とまったく同一です。
QColor("#7F7F7F")
QColor("#808080")
QColor("#7F7F7F")
QColor("#808080")

color: "#ff0000" 

参考情報

QColor Class
color QML Basic Type

SVG 色名と X11 色名

SVG 色名と X11 色名の一覧を表示して比較するプログラムです。
x11rgbtext.h:

#pragma once

#include <QRegularExpression>
#include <QStringList>

class X11RGBText
{
private:
    X11RGBText();
    virtual ~X11RGBText() = default;

    void init();

public:
    X11RGBText(const X11RGBText&) = delete;
    X11RGBText& operator=(const X11RGBText&) = delete;
    X11RGBText(X11RGBText&&) = delete;
    X11RGBText& operator=(X11RGBText&&) = delete;

    static X11RGBText& instance();

    QStringList names() const;
    QColor color(const QString& name) const;

private:
    QStringList colorNames;
    QHash<QString, QColor> x11rgbTextHash;
};
names() は X11 色名のリストを返し、color() は指定した色名の QColor を返します。
x11rgbtext.cpp:

#include "x11rgbtext.h"
#include <QTextStream>
#include <QScrollArea>
#include <QRegularExpression>
#include <QFile>

X11RGBText::X11RGBText()
{
    init();
}

X11RGBText& X11RGBText::instance() {
    static X11RGBText x11rgbText;
    return x11rgbText;
}

QStringList X11RGBText::names() const {
    return colorNames;
}

QColor X11RGBText::color(const QString& name) const
{
    return *x11rgbTextHash.find(name);
}

void X11RGBText::init()
{
    const QRegularExpression leadingWhiteSpacesRegularExpression = QRegularExpression("^\\s+");
    const QRegularExpression startWithDigitRegularExpression = QRegularExpression("^[0-9]");

    for (const QString& rgbTextFileName : { "/etc/X11/rgb.txt",
                                            "/usr/lib/X11/rgb.txt",
                                            "/usr/share/X11/rgb.txt",
                                            "/opt/X11/share/X11/rgb.txt",
                                            "/usr/share/emacs/22.1/etc/rgb.txt",
                                            "/opt/local/share/netpbm/rgb.txt" }) {
        QFile rgbTextFile(rgbTextFileName);
        if (rgbTextFile.open(QIODevice::ReadOnly)) {
            QTextStream rgbTextInputStream(&rgbTextFile);
            while (!rgbTextInputStream.atEnd()) {
                QString line = rgbTextInputStream.readLine();
                line = line.replace(leadingWhiteSpacesRegularExpression, "");
                if (!line.contains(startWithDigitRegularExpression)) {
                    continue;
                }
                QTextStream lineStream(&line);
                int r, g, b;
                QString colorName;
                lineStream >> r >> g >> b;
                colorName = lineStream.readAll().trimmed();
                colorNames.append(colorName);
                x11rgbTextHash.insert(colorName, QColor(r, g, b));
            }
            break;
        }
    }
}
rgb.txt ファイルは以降のような形式で記述されています。init() では色を定義している行を探して、色名を QStringList 型の colorNames に入れ、 色名をキーにして色を求めるために QHash<QString, QColor> 型の x11rgbTextHash に登録しています。
/etc/X11/rgb.txt:
! $Xorg: rgb.txt,v 1.3 2000/08/17 19:54:00 cpqbld Exp $
255 250 250             snow
248 248 255             ghost white
248 248 255             GhostWhite
245 245 245             white smoke
245 245 245             WhiteSmoke
...
/opt/local/share/netpbm/rgb.txt:
# The colors in this color dictionary are from the following sources, in
# order.  Some color names are defined multiple times, and sometimes
# with different colors.  Many colors have multiple names.
...
  0   0   0 Black
255 255 255 White
255   0   0 Red
  0 255   0 Green
  0   0 255 Blue
  0 255 255 Cyan
...
colorstack.h:

#pragma once

#include <QWidget>

class ColorStack : public QWidget
{
    Q_OBJECT

public:
    explicit ColorStack(const QStringList& colors, QWidget* parent = 0);
    bool eventFilter(QObject* watched, QEvent* event) override;
};
色名の一覧を表示するウィジェットです。
colorstack.cpp:

#include "colorstack.h"
#include "x11rgbtext.h"
#include <QLayout>
#include <QLabel>
#include <QToolTip>
#include <QHelpEvent>

ColorStack::ColorStack(const QStringList& colorNames, QWidget* parent)
    : QWidget(parent)
{
    const auto topLayout = new QVBoxLayout(this);
    topLayout->setSpacing(0);
    topLayout->setMargin(0);

    for (const QString& colorName : qAsConst(colorNames)) {
        QColor color(colorName);

        auto colorLabel = new QLabel(colorName);
        colorLabel->setAutoFillBackground(true);
        QPalette colorLabelPalette = colorLabel->palette();
        if (color.isValid()) {
            colorLabelPalette.setColor(QPalette::Window, color);
        } else {
            color = X11RGBText::instance().color(colorName);
            colorLabelPalette.setColor(QPalette::Window, color);
        }

        // Choose a proper text color for the background color.
        int gray = 0;
        if (color.isValid()) {
            if (colorName.compare("transparent", Qt::CaseInsensitive) == 0) {  // Qt extension to SVG color names
                gray = qGray(colorLabel->palette().color(QPalette::Window).rgb());
            } else {
                gray = qGray(color.rgb());
            }
        }
        if (double(gray) > (255.0 / 2.0)) {
            colorLabelPalette.setColor(QPalette::WindowText, "Black");
        } else {
            colorLabelPalette.setColor(QPalette::WindowText, "White");
        }

        colorLabel->setPalette(colorLabelPalette);
        colorLabel->installEventFilter(this);
        topLayout->addWidget(colorLabel);
    }
}

bool ColorStack::eventFilter(QObject* watched, QEvent* event)
{
    if (event->type() == QEvent::ToolTip) {
        const QHelpEvent* const helpEvent = static_cast<QHelpEvent*>(event);
        QLabel* const label = qobject_cast<QLabel*>(watched);
        if (label) {
            const QColor color = label->palette().color(QPalette::Window);
            QToolTip::showText(helpEvent->globalPos(), color.name());
        }
    }
    return false;
}
イベントフィルターでは表示されている色名のラベルの上にマウスカーソルが来たときに 16 進数で色名を表示しています。
harness.h:

#pragma once

#include "colorstack.h"
#include "x11rgbtext.h"
#include <QWidget>

class Harness : public QWidget
{
    Q_OBJECT

public:
    Harness();
};
SVG 色名の一覧と X11 色名の一覧を横に並べて表示するウィジェットです。
harness.cpp:

#include "harness.h"
#include "x11rgbtext.h"
#include <QLayout>
#include <QLabel>
#include <QScrollArea>

Harness::Harness()
    : QWidget(0)
{
    auto topLayout = new QHBoxLayout(this);

    auto addColorStack = [&](const QString& title, ColorStack* const colorStack) {
        auto colorStackLayout = new QVBoxLayout;

        colorStackLayout->addWidget(new QLabel(title));

        const auto scrollArea = new QScrollArea;
        scrollArea->setWidgetResizable(true);
        scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
        scrollArea->setWidget(colorStack);
        colorStackLayout->addWidget(scrollArea);

        topLayout->addLayout(colorStackLayout);
    };

    addColorStack("SVG name", new ColorStack(QColor::colorNames()));
    addColorStack("rgb.txt", new ColorStack(X11RGBText::instance().names()));
}

main.cpp:

#include "harness.h"
#include <QApplication>

int main(int argc, char** argv)
{
    QApplication app(argc, argv);

    Harness harness;
    harness.show();

    return app.exec();
}

macOS と Ubuntu で実行した結果です。

macOS での実行結果
Ubuntu での実行結果

参考情報

QColor Class
ウェブカラー