From bf84987bc5d9a5d100948aeabdb1d47b35a7961e Mon Sep 17 00:00:00 2001
From: EndrII <EndrIIMail@gmail.com>
Date: Wed, 26 Oct 2022 00:24:54 +0300
Subject: [PATCH 1/5] ref #728 added test of qml files dialogs

---
 testcases/CMakeLists.txt                |  3 +-
 testcases/QMLFileDialog/CMakeLists.txt  | 21 +++++++++++
 testcases/QMLFileDialog/main.cpp        | 19 ++++++++++
 testcases/QMLFileDialog/main.qml        | 33 +++++++++++++++++
 tests/tstMain.cpp                       |  4 ++
 tests/units/linux/qmlfiledialogtest.cpp | 49 +++++++++++++++++++++++++
 tests/units/linux/qmlfiledialogtest.h   | 23 ++++++++++++
 7 files changed, 151 insertions(+), 1 deletion(-)
 create mode 100644 testcases/QMLFileDialog/CMakeLists.txt
 create mode 100644 testcases/QMLFileDialog/main.cpp
 create mode 100644 testcases/QMLFileDialog/main.qml
 create mode 100644 tests/units/linux/qmlfiledialogtest.cpp
 create mode 100644 tests/units/linux/qmlfiledialogtest.h

diff --git a/testcases/CMakeLists.txt b/testcases/CMakeLists.txt
index a5153d6..7c44ed5 100644
--- a/testcases/CMakeLists.txt
+++ b/testcases/CMakeLists.txt
@@ -14,9 +14,10 @@ add_subdirectory(TestCPPOnly)
 add_subdirectory(TestOnlyC)
 add_subdirectory(TestQMLWidgets)
 add_subdirectory(TestQtWidgets)
-add_subdirectory(virtualkeyboard)
 
 if (NOT WIN32)
+    add_subdirectory(QMLFileDialog)
+    add_subdirectory(virtualkeyboard)
     add_subdirectory(quicknanobrowser)
     add_subdirectory(webui)
 endif()
diff --git a/testcases/QMLFileDialog/CMakeLists.txt b/testcases/QMLFileDialog/CMakeLists.txt
new file mode 100644
index 0000000..30e6112
--- /dev/null
+++ b/testcases/QMLFileDialog/CMakeLists.txt
@@ -0,0 +1,21 @@
+cmake_minimum_required(VERSION 3.16)
+
+project(QMLFileDialog LANGUAGES CXX)
+
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+
+find_package(Qt6 COMPONENTS Quick REQUIRED)
+
+qt_add_executable(QMLFileDialog
+    main.cpp
+)
+
+qt_add_qml_module(QMLFileDialog
+    URI QMLFileDialog
+    VERSION 1.0
+    QML_FILES main.qml 
+)
+
+target_link_libraries(QMLFileDialog
+    PRIVATE Qt6::Quick)
diff --git a/testcases/QMLFileDialog/main.cpp b/testcases/QMLFileDialog/main.cpp
new file mode 100644
index 0000000..ad40580
--- /dev/null
+++ b/testcases/QMLFileDialog/main.cpp
@@ -0,0 +1,19 @@
+#include <QGuiApplication>
+#include <QQmlApplicationEngine>
+
+
+int main(int argc, char *argv[])
+{
+    QGuiApplication app(argc, argv);
+
+    QQmlApplicationEngine engine;
+    const QUrl url(u"qrc:/QMLFileDialog/main.qml"_qs);
+    QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
+        &app, [url](QObject *obj, const QUrl &objUrl) {
+            if (!obj && url == objUrl)
+                QCoreApplication::exit(-1);
+        }, Qt::QueuedConnection);
+    engine.load(url);
+
+    return app.exec();
+}
diff --git a/testcases/QMLFileDialog/main.qml b/testcases/QMLFileDialog/main.qml
new file mode 100644
index 0000000..cd21e8e
--- /dev/null
+++ b/testcases/QMLFileDialog/main.qml
@@ -0,0 +1,33 @@
+import QtCore
+import QtQuick
+import QtQuick.Dialogs
+import QtQuick.Controls
+
+ApplicationWindow {
+    width: 640
+    height: 480
+    visible: true
+    title: qsTr("Hello World")
+
+
+
+
+    header: ToolBar {
+        Button {
+            text: qsTr("Choose Image...")
+            onClicked: fileDialog.open()
+        }
+    }
+
+    Image {
+        id: image
+        anchors.fill: parent
+        fillMode: Image.PreserveAspectFit
+    }
+
+    FileDialog {
+        id: fileDialog
+        currentFolder: StandardPaths.standardLocations(StandardPaths.PicturesLocation)[0]
+        onAccepted: image.source = selectedFile
+    }
+}
diff --git a/tests/tstMain.cpp b/tests/tstMain.cpp
index 9689c0a..972e40c 100644
--- a/tests/tstMain.cpp
+++ b/tests/tstMain.cpp
@@ -65,6 +65,7 @@
 #include "zipmultitest.h"
 #include "ziptest.h"
 #include "systemlibtest.h"
+#include "qmlfiledialogtest.h"
 #endif
 
 #ifdef Q_OS_WIN
@@ -156,6 +157,9 @@ private slots:
         TestCase(zipmultitest, ZIPMultiTest )
         TestCase(ziptest, ZIPTest )
         TestCase(systemLibTest, SystemLibTest)
+        TestCase(qmlfiledialogtest, QmlFileDialogTest)
+
+
 #endif
 
 //     platform tests
diff --git a/tests/units/linux/qmlfiledialogtest.cpp b/tests/units/linux/qmlfiledialogtest.cpp
new file mode 100644
index 0000000..fdc3fe9
--- /dev/null
+++ b/tests/units/linux/qmlfiledialogtest.cpp
@@ -0,0 +1,49 @@
+//#
+//# Copyright (C) 2020-2022 QuasarApp.
+//# Distributed under the GPLv3 software license, see the accompanying
+//# Everyone is permitted to copy and distribute verbatim copies
+//# of this license document, but changing it is not allowed.
+//#
+
+
+#include "qmlfiledialogtest.h"
+#include <configparser.h>
+#include <dependenciesscanner.h>
+#include <filemanager.h>
+#include <packing.h>
+#include <pluginsparser.h>
+#include "modules.h"
+
+
+void QmlFileDialogTest::test() {
+    
+    TestUtils utils;
+
+    auto compareTree = TestModule.qmlLibs();
+
+    compareTree = TestModule.ignoreFilter(compareTree, "TestQMLWidgets");
+
+    compareTree += utils.createTree(
+        {
+            "./" + DISTRO_DIR + "/QMLFileDialog.sh",
+            "./" + DISTRO_DIR + "/bin/QMLFileDialog",
+            "./" + DISTRO_DIR + "/lib/libQt6QmlCore.so",
+            "./" + DISTRO_DIR + "/lib/libQt6QuickDialogs2.so",
+            "./" + DISTRO_DIR + "/lib/libQt6QuickDialogs2QuickImpl.so",
+            "./" + DISTRO_DIR + "/lib/libQt6QuickDialogs2Utils.so",
+            "./" + DISTRO_DIR + "/qml/QtCore/libqtqmlcoreplugin.so",
+            "./" + DISTRO_DIR + "/qml/QtCore/plugins.qmltypes",
+            "./" + DISTRO_DIR + "/qml/QtCore/qmldir",
+            "./" + DISTRO_DIR + "/qml/QtQuick/Dialogs/libqtquickdialogsplugin.so",
+            "./" + DISTRO_DIR + "/qml/QtQuick/Dialogs/plugins.qmltypes",
+            "./" + DISTRO_DIR + "/qml/QtQuick/Dialogs/qmldir"
+        }
+        );
+
+    auto bin = TestBinDir + "QMLFileDialog";
+
+    runTestParams({"-bin", bin, "clear" ,
+                   "-qmlDir", TestBinDir + "/../QMLFileDialog"}, &compareTree);
+
+}
+
diff --git a/tests/units/linux/qmlfiledialogtest.h b/tests/units/linux/qmlfiledialogtest.h
new file mode 100644
index 0000000..8a790f2
--- /dev/null
+++ b/tests/units/linux/qmlfiledialogtest.h
@@ -0,0 +1,23 @@
+//#
+//# Copyright (C) 2020-2022 QuasarApp.
+//# Distributed under the GPLv3 software license, see the accompanying
+//# Everyone is permitted to copy and distribute verbatim copies
+//# of this license document, but changing it is not allowed.
+//#
+
+
+#ifndef QML_FILE_DIALOG_TEST_H
+#define QML_FILE_DIALOG_TEST_H
+#include "testbase.h"
+#include "testutils.h"
+
+#include <QtTest>
+
+class QmlFileDialogTest: public TestBase, protected TestUtils
+{
+public:
+    void test() override;
+
+};
+
+#endif // QML_FILE_DIALOG_TEST_H

From 70c6e5f3059c83039c4a0e84fb24b94614ac54e7 Mon Sep 17 00:00:00 2001
From: EndrII <EndrIIMail@gmail.com>
Date: Wed, 26 Oct 2022 00:53:08 +0300
Subject: [PATCH 2/5] fix linux tests

---
 tests/units/linux/extradatatest.cpp | 11 +----------
 1 file changed, 1 insertion(+), 10 deletions(-)

diff --git a/tests/units/linux/extradatatest.cpp b/tests/units/linux/extradatatest.cpp
index 10376a9..ccaaf09 100644
--- a/tests/units/linux/extradatatest.cpp
+++ b/tests/units/linux/extradatatest.cpp
@@ -18,24 +18,15 @@
 void ExtraDataTest::test() {
     TestUtils utils;
 
-
-#ifdef Q_OS_UNIX
     auto comapareTree = utils.createTree(
                 {"./" + DISTRO_DIR + "/bin/TestOnlyC",
                  "./" + DISTRO_DIR + "/bin/TestCPPOnly",
                  "./" + DISTRO_DIR + "/bin/QtWidgetsProject",
                  "./" + DISTRO_DIR + "/bin/TestQMLWidgets",
+                 "./" + DISTRO_DIR + "/bin/QMLFileDialog",
                  "./" + DISTRO_DIR + "/bin/basic",
                  "./" + DISTRO_DIR + "/bin/quicknanobrowser",
                  "./" + DISTRO_DIR + "/bin/webui"});
-#else
-    auto comapareTree = utils.createTree(
-                {"./" + DISTRO_DIR + "/b    in/TestOnlyC.exe",
-                 "./" + DISTRO_DIR + "/bin/TestCPPOnly.exe",
-                 "./" + DISTRO_DIR + "/bin/QtWidgetsProject.exe",
-                 "./" + DISTRO_DIR + "/bin/TestQMLWidgets.exe",
-                 "./" + DISTRO_DIR + "/bin/basic.exe"});
-#endif
 
 
     runTestParams({"-extraData", TestBinDir, "clear",

From d61172c64ad975291988b73fa709f9e35be11db6 Mon Sep 17 00:00:00 2001
From: EndrII <EndrIIMail@gmail.com>
Date: Wed, 26 Oct 2022 10:26:40 +0300
Subject: [PATCH 3/5] back port qml scaner from cqtdeployer 1.5

---
 src/Deploy/src/extracter.cpp           |  12 +-
 src/Deploy/src/extracter.h             |   2 +-
 src/Deploy/src/iqml.cpp                |  13 ++
 src/Deploy/src/iqml.h                  |  40 +++++
 src/Deploy/src/{qml.cpp => qmlqt5.cpp} |  47 ++---
 src/Deploy/src/{qml.h => qmlqt5.h}     |  19 +--
 src/Deploy/src/qmlqt6.cpp              | 226 +++++++++++++++++++++++++
 src/Deploy/src/qmlqt6.h                |  45 +++++
 tests/units/linux/qmlextracttest.cpp   |   4 +-
 tests/units/linux/qmlscanertest.cpp    |  62 +------
 10 files changed, 370 insertions(+), 100 deletions(-)
 create mode 100644 src/Deploy/src/iqml.cpp
 create mode 100644 src/Deploy/src/iqml.h
 rename src/Deploy/src/{qml.cpp => qmlqt5.cpp} (79%)
 rename src/Deploy/src/{qml.h => qmlqt5.h} (70%)
 create mode 100644 src/Deploy/src/qmlqt6.cpp
 create mode 100644 src/Deploy/src/qmlqt6.h

diff --git a/src/Deploy/src/extracter.cpp b/src/Deploy/src/extracter.cpp
index cffa61f..4ae4206 100644
--- a/src/Deploy/src/extracter.cpp
+++ b/src/Deploy/src/extracter.cpp
@@ -10,6 +10,7 @@
 #include "pluginsparser.h"
 #include "configparser.h"
 #include "metafilemanager.h"
+#include "qmlqt5.h"
 #include <QCoreApplication>
 #include <QDebug>
 #include <QDir>
@@ -464,13 +465,20 @@ bool Extracter::extractQml() {
                     continue;
                 }
 
-                QML ownQmlScaner(cnf->qtDir.getQmls(), cnf->isNeededQt(i.key()));
+                auto QtVersion = cnf->isNeededQt(i.key());
+                QSharedPointer<iQML> qmlScaner;
+                if (QtVersion & QtMajorVersion::Qt6) {
+                    qmlScaner = QSharedPointer<QMLQt6>::create(cnf->qtDir.getQmls());
+                } else if (QtVersion & QtMajorVersion::Qt5) {
+                    qmlScaner = QSharedPointer<QMLQt5>::create(cnf->qtDir.getQmls());
+                }
 
-                if (!ownQmlScaner.scan(plugins, info.absoluteFilePath())) {
+                if (qmlScaner && !qmlScaner->scan(plugins, info.absoluteFilePath())) {
                     QuasarAppUtils::Params::log("Failed to run qml scanner",
                                                 QuasarAppUtils::Error);
                     continue;
                 }
+
             }
 
 
diff --git a/src/Deploy/src/extracter.h b/src/Deploy/src/extracter.h
index 0b893c7..2a07f81 100644
--- a/src/Deploy/src/extracter.h
+++ b/src/Deploy/src/extracter.h
@@ -14,7 +14,7 @@
 #include "dependencymap.h"
 #include "deploy_global.h"
 #include "filemanager.h"
-#include "qml.h"
+#include "qmlqt6.h"
 
 class ConfigParser;
 class MetaFileManager;
diff --git a/src/Deploy/src/iqml.cpp b/src/Deploy/src/iqml.cpp
new file mode 100644
index 0000000..85d875c
--- /dev/null
+++ b/src/Deploy/src/iqml.cpp
@@ -0,0 +1,13 @@
+//#
+//# Copyright (C) 2022-2022 QuasarApp.
+//# Distributed under the lgplv3 software license, see the accompanying
+//# Everyone is permitted to copy and distribute verbatim copies
+//# of this license document, but changing it is not allowed.
+//#
+
+
+#include "iqml.h"
+
+iQML::iQML(const QString &qmlRoot) {
+    _qmlRoot = qmlRoot;
+}
diff --git a/src/Deploy/src/iqml.h b/src/Deploy/src/iqml.h
new file mode 100644
index 0000000..d5b0900
--- /dev/null
+++ b/src/Deploy/src/iqml.h
@@ -0,0 +1,40 @@
+//#
+//# Copyright (C) 2022-2022 QuasarApp.
+//# Distributed under the lgplv3 software license, see the accompanying
+//# Everyone is permitted to copy and distribute verbatim copies
+//# of this license document, but changing it is not allowed.
+//#
+
+#ifndef IQML_H
+#define IQML_H
+
+#include <QString>
+#include "deploy_global.h"
+
+/**
+ * @brief The iQML class Bae interface for scannin qml depends.
+ */
+class DEPLOYSHARED_EXPORT iQML
+{
+public:
+
+    /**
+     * @brief iQML base constructor
+     * @param qmlRoot This is qml root dir of Qt destribution. Example: Qt/6.4.0/gcc_64/qml
+     */
+    iQML(const QString& qmlRoot);
+    virtual ~iQML() = default;
+
+    /**
+     * @brief scan This method scane qml files in the qmlRoot and return needed to deploy files
+     * @param res This is result of scan.  List of needed to deploy files
+     * @param _qmlProjectDir This is
+     * @return true if function finished succesful
+     */
+    virtual bool scan(QStringList &res, const QString &_qmlProjectDir) = 0;
+
+protected:
+    QString _qmlRoot;
+};
+
+#endif // IQML_H
diff --git a/src/Deploy/src/qml.cpp b/src/Deploy/src/qmlqt5.cpp
similarity index 79%
rename from src/Deploy/src/qml.cpp
rename to src/Deploy/src/qmlqt5.cpp
index f9beb90..de1f04e 100644
--- a/src/Deploy/src/qml.cpp
+++ b/src/Deploy/src/qmlqt5.cpp
@@ -5,7 +5,7 @@
  * of this license document, but changing it is not allowed.
  */
 
-#include "qml.h"
+#include "qmlqt5.h"
 
 #include <QDir>
 #include <QFile>
@@ -13,18 +13,18 @@
 #include "deploycore.h"
 #include "qregularexpression.h"
 
-QStringList QML::extractImportLine(const QString& line) const {
+QStringList QMLQt5::extractImportLine(const QString& line) const {
     QStringList result;
     QStringList list = line.split(" ", splitbehavior);
 
     if (list.count() == 3 || (list.count() == 5  && list[3] == "as")) {
-        if (list[2] == "auto" || (_qtVersion & QtMajorVersion::Qt6)) {
+        if (list[2] == "auto") {
             // qt6
             result << (list[1].replace(".", "/"));
             return result;
         }
         // qt5
-        result << (list[2][0] + QString("#") + list[1].replace(".", "/"));
+        result << (QString(list[2][0]) + "#" + list[1].replace(".", "/"));
     } else if (list.count() == 2 || (list.count() == 4  && list[2] == "as")) {
         // qt6
         result << (list[1].replace(".", "/"));
@@ -33,7 +33,7 @@ QStringList QML::extractImportLine(const QString& line) const {
     return result;
 }
 
-QStringList QML::extractImportsFromFile(const QString &filepath) const {
+QStringList QMLQt5::extractImportsFromFile(const QString &filepath) const {
     QStringList imports;
     QFile F(filepath);
     if (!F.open(QIODevice::ReadOnly)) return QStringList();
@@ -65,7 +65,7 @@ QStringList QML::extractImportsFromFile(const QString &filepath) const {
     return imports;
 }
 
-bool QML::extractImportsFromDir(const QString &path, bool recursive) {
+bool QMLQt5::extractImportsFromDir(const QString &path, bool recursive) {
     QDir dir(path);
 
     if (!dir.isReadable()) {
@@ -82,33 +82,22 @@ bool QML::extractImportsFromDir(const QString &path, bool recursive) {
         for (const auto &import : qAsConst(imports)) {
             if (!_imports.contains(import)) {
                 _imports.insert(import);
-                extractImportsFromDir(getPathFromImport(import), false);
+                extractImportsFromDir(getPathFromImport(import), recursive);
             }
         }
     }
 
     for (const auto& module: qAsConst(qmlmodule)) {
         QStringList imports = extractImportsFromQmlModule(module.absoluteFilePath());
-        imports += extractImportsFromFile(module.absoluteFilePath());
 
         for (const auto &import : qAsConst(imports)) {
             if (!_imports.contains(import)) {
                 _imports.insert(import);
-                extractImportsFromDir(getPathFromImport(import), false);
+                extractImportsFromDir(getPathFromImport(import), recursive);
             }
         }
     }
 
-    // task https://github.com/QuasarApp/CQtDeployer/issues/600
-    // There are no import lines for the qt models module in Qt 6.1, but this module is required for all qml applications.
-    if (_qtVersion & QtMajorVersion::Qt6) {
-        auto importQtQml = "QtQml";
-        if (!_imports.contains(importQtQml)) {
-            _imports.insert(importQtQml);
-            extractImportsFromDir(getPathFromImport(importQtQml), false);
-        }
-    }
-
     if (recursive) {
         for (const auto &info: dirs) {
             extractImportsFromDir(info.absoluteFilePath(), recursive);
@@ -118,7 +107,7 @@ bool QML::extractImportsFromDir(const QString &path, bool recursive) {
     return true;
 }
 
-QString QML::getPathFromImport(const QString &import, bool checkVersions) {
+QString QMLQt5::getPathFromImport(const QString &import, bool checkVersions) {
     if (!import.contains("#")) {
         // qt 6
         auto info = QFileInfo(_qmlRoot + "/" + import);
@@ -136,6 +125,7 @@ QString QML::getPathFromImport(const QString &import, bool checkVersions) {
     } else {
         return "";
     }
+
     QRegularExpression matcher;
     matcher.setPattern("[/\\\\]");
     auto words = importData.value(index).split(matcher);
@@ -161,7 +151,7 @@ QString QML::getPathFromImport(const QString &import, bool checkVersions) {
     return info.absoluteFilePath();
 }
 
-bool QML::deployPath(const QString &path, QStringList &res) {
+bool QMLQt5::deployPath(const QString &path, QStringList &res) {
     QDir dir(path);
     auto infoList = dir.entryInfoList(QDir::NoDotAndDotDot | QDir::Files | QDir::Dirs);
 
@@ -178,7 +168,7 @@ bool QML::deployPath(const QString &path, QStringList &res) {
     return true;
 }
 
-bool QML::scanQmlTree(const QString &qmlTree) {
+bool QMLQt5::scanQmlTree(const QString &qmlTree) {
     QDir dir(qmlTree);
 
     if (!dir.isReadable()) {
@@ -198,7 +188,7 @@ bool QML::scanQmlTree(const QString &qmlTree) {
     return true;
 }
 
-QStringList QML::extractImportsFromQmlModule(const QString &module) const {
+QStringList QMLQt5::extractImportsFromQmlModule(const QString &module) const {
     QStringList imports;
     QFile F(module);
     if (!F.open(QIODevice::ReadOnly)) return QStringList();
@@ -217,17 +207,12 @@ QStringList QML::extractImportsFromQmlModule(const QString &module) const {
     return imports;
 }
 
-void QML::setQtVersion(const QtMajorVersion &qtVersion) {
-    _qtVersion = qtVersion;
-}
 
-QML::QML(const QString &qmlRoot, QtMajorVersion qtVersion) {
-    _qmlRoot = qmlRoot;
-    setQtVersion(qtVersion);
+QMLQt5::QMLQt5(const QString &qmlRoot): iQML(qmlRoot) {}
 
-}
+QMLQt5::~QMLQt5() {}
 
-bool QML::scan(QStringList &res, const QString& _qmlProjectDir) {
+bool QMLQt5::scan(QStringList &res, const QString& _qmlProjectDir) {
 
     if (!scanQmlTree(_qmlRoot)) {
         return false;
diff --git a/src/Deploy/src/qml.h b/src/Deploy/src/qmlqt5.h
similarity index 70%
rename from src/Deploy/src/qml.h
rename to src/Deploy/src/qmlqt5.h
index eac9dba..b062c1b 100644
--- a/src/Deploy/src/qml.h
+++ b/src/Deploy/src/qmlqt5.h
@@ -5,15 +5,14 @@
 //# of this license document, but changing it is not allowed.
 //#
 
-#ifndef QML_DEPLY_H
-#define QML_DEPLY_H
+#ifndef QML_QT5_DEPLY_H
+#define QML_QT5_DEPLY_H
 
 #include <QSet>
 #include <QStringList>
-#include "deploy_global.h"
-#include "deploycore.h"
+#include "iqml.h"
 
-class DEPLOYSHARED_EXPORT QML {
+class DEPLOYSHARED_EXPORT QMLQt5: public iQML {
 private:
 
     QStringList extractImportsFromFile(const QString &filepath) const;
@@ -25,22 +24,20 @@ private:
     bool deployPath( const QString& path, QStringList& res);
     bool scanQmlTree(const QString& qmlTree);
     QStringList extractImportsFromQmlModule(const QString& module) const;
-    QString _qmlRoot = "";
     QSet<QString> _imports;
     QSet<QString> secondVersions;
-    QtMajorVersion _qtVersion = QtMajorVersion::Qt5;
 
     QStringList extractImportLine(const QString &line) const;
     
 public:
-    QML(const QString& qmlRoot, QtMajorVersion isQt6);
+    QMLQt5(const QString& qmlRoot);
+    ~QMLQt5() override;
 
-    bool scan(QStringList &res, const QString &_qmlProjectDir);
-    void setQtVersion(const QtMajorVersion &qtVersion);
+    bool scan(QStringList &res, const QString &_qmlProjectDir) override;
 
     friend class deploytest;
     friend class QmlScanerTest;
     friend class QMLExtractTest;
 };
 
-#endif // QML_DEPLY_H
+#endif // QML_QT5_DEPLY_H
diff --git a/src/Deploy/src/qmlqt6.cpp b/src/Deploy/src/qmlqt6.cpp
new file mode 100644
index 0000000..9784e55
--- /dev/null
+++ b/src/Deploy/src/qmlqt6.cpp
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) 2018-2022 QuasarApp.
+ * Distributed under the lgplv3 software license, see the accompanying
+ * Everyone is permitted to copy and distribute verbatim copies
+ * of this license document, but changing it is not allowed.
+ */
+
+#include "qmlqt6.h"
+
+#include <QDir>
+#include <QFile>
+#include "defines.h"
+#include "deploycore.h"
+#include "qregularexpression.h"
+
+QStringList QMLQt6::extractImportLine(const QString& line) const {
+    QStringList result;
+    QStringList list = line.split(" ", splitbehavior);
+
+    result << (list[1].replace(".", "/"));
+    return result;
+
+    return result;
+}
+
+QStringList QMLQt6::extractImportsFromFile(const QString &filepath) const {
+    QStringList imports;
+    QFile F(filepath);
+    if (!F.open(QIODevice::ReadOnly)) return QStringList();
+
+    QString content = F.readAll();
+    QRegularExpression matcher;
+
+    matcher.setPattern("\\{(.*)\\}");
+    content.remove(matcher);
+
+    matcher.setPattern("/\\*(.*)\\*/");
+    content.remove(matcher);
+
+    // Replace optional imports to restrict option, because before Qt 6.3 The Qml app needee of optional qml packas.
+    content.replace("optional import", "import");
+
+
+    const auto list = content.split("\n");
+    for (const QString &line : list)
+        for (QString &word : line.split(";", splitbehavior))
+        {
+            word = word.simplified();
+            if (word.startsWith("//")) continue;
+            if (!word.startsWith("import")) continue;
+
+            imports += extractImportLine(word);
+        }
+
+    return imports;
+}
+
+bool QMLQt6::extractImportsFromDir(const QString &path, bool recursive) {
+    QDir dir(path);
+
+    if (!dir.isReadable()) {
+        return false;
+    }
+
+    auto files = dir.entryInfoList(QStringList() << "*.qml" << "*.QML", QDir::Files);
+    auto qmlmodule = dir.entryInfoList(QStringList() << "qmldir", QDir::Files);
+
+    auto dirs = dir.entryInfoList(QDir::NoDotAndDotDot | QDir::Dirs);
+
+    for (const auto &info: files) {
+        auto imports = extractImportsFromFile(info.absoluteFilePath());
+        for (const auto &import : qAsConst(imports)) {
+            if (!_imports.contains(import)) {
+                _imports.insert(import);
+                extractImportsFromDir(getPathFromImport(import), false);
+            }
+        }
+    }
+
+    for (const auto& module: qAsConst(qmlmodule)) {
+        QStringList imports = extractImportsFromQmlModule(module.absoluteFilePath());
+        imports += extractImportsFromFile(module.absoluteFilePath());
+
+        for (const auto &import : qAsConst(imports)) {
+            if (!_imports.contains(import)) {
+                _imports.insert(import);
+                extractImportsFromDir(getPathFromImport(import), false);
+            }
+        }
+    }
+
+    // task https://github.com/QuasarApp/CQtDeployer/issues/600
+    // There are no import lines for the qt models module in Qt 6.1, but this module is required for all qml applications.
+    auto importQtQml = "QtQml";
+    if (!_imports.contains(importQtQml)) {
+        _imports.insert(importQtQml);
+        extractImportsFromDir(getPathFromImport(importQtQml), false);
+    }
+
+    if (recursive) {
+        for (const auto &info: dirs) {
+            extractImportsFromDir(info.absoluteFilePath(), recursive);
+        }
+    }
+
+    return true;
+}
+
+QString QMLQt6::getPathFromImport(const QString &import, bool checkVersions) {
+    if (!import.contains("#")) {
+        // qt 6
+        auto info = QFileInfo(_qmlRoot + "/" + import);
+        return info.absoluteFilePath();
+    }
+
+    auto importData = import.split("#");
+
+    int index;
+
+    if (importData.size() == 2)
+        index = 1;
+    else if (!importData.isEmpty()) {
+        index = 0;
+    } else {
+        return "";
+    }
+    QRegularExpression matcher;
+    matcher.setPattern("[/\\\\]");
+    auto words = importData.value(index).split(matcher);
+    const bool isSecond = importData.first() == "2" && checkVersions;
+    bool secondVersion = isSecond;
+
+    QString path;
+    for (auto i = words.rbegin(); i != words.rend(); ++i) {
+        QString word = *i;
+        if (secondVersion && secondVersions.contains(word)) {
+            secondVersion = false;
+            word.push_back(".2");
+        }
+
+        path.push_front(word + "/");
+    }
+    auto info = QFileInfo(_qmlRoot + "/" + path);
+
+    if (isSecond && !info.exists()) {
+        return getPathFromImport(import, false);
+    }
+
+    return info.absoluteFilePath();
+}
+
+bool QMLQt6::deployPath(const QString &path, QStringList &res) {
+    QDir dir(path);
+    auto infoList = dir.entryInfoList(QDir::NoDotAndDotDot | QDir::Files | QDir::Dirs);
+
+    for (const auto &info : qAsConst(infoList)) {
+        if (DeployCore::isDebugFile(info.fileName())) {
+            QuasarAppUtils::Params::log("Skip debug library " +
+                                        info.absoluteFilePath());
+            continue;
+        }
+
+        res.push_back(info.absoluteFilePath());
+    }
+
+    return true;
+}
+
+bool QMLQt6::scanQmlTree(const QString &qmlTree) {
+    QDir dir(qmlTree);
+
+    if (!dir.isReadable()) {
+        return false;
+    }
+
+    auto list = dir.entryInfoList( QDir::Dirs | QDir::NoDotAndDotDot);
+
+    for (const auto &info : list) {
+        if (info.fileName().contains(".2")) {
+            secondVersions.insert(info.fileName().left(info.fileName().size() - 2));
+        }
+        scanQmlTree(info.absoluteFilePath());
+
+    }
+
+    return true;
+}
+
+QStringList QMLQt6::extractImportsFromQmlModule(const QString &module) const {
+    QStringList imports;
+    QFile F(module);
+    if (!F.open(QIODevice::ReadOnly)) return QStringList();
+
+    QString content = F.readAll();
+    const auto list = content.split("\n");
+    for (QString line : list) {
+        line = line.simplified();
+        if (line.startsWith("//") || line.startsWith("#")) continue;
+        if (!line.startsWith("depends")) continue;
+
+        imports += extractImportLine(line);
+    }
+
+    return imports;
+}
+
+QMLQt6::QMLQt6(const QString &qmlRoot): iQML(qmlRoot) {}
+
+QMLQt6::~QMLQt6(){}
+
+bool QMLQt6::scan(QStringList &res, const QString& _qmlProjectDir) {
+
+    if (!scanQmlTree(_qmlRoot)) {
+        return false;
+    }
+
+    if (!extractImportsFromDir(_qmlProjectDir, true)) {
+        return false;
+    }
+
+    for (const auto &import : qAsConst(_imports)) {
+        res.push_back(getPathFromImport(import));
+    }
+
+    return true;
+}
diff --git a/src/Deploy/src/qmlqt6.h b/src/Deploy/src/qmlqt6.h
new file mode 100644
index 0000000..c4c6c46
--- /dev/null
+++ b/src/Deploy/src/qmlqt6.h
@@ -0,0 +1,45 @@
+//#
+//# Copyright (C) 2018-2022 QuasarApp.
+//# Distributed under the lgplv3 software license, see the accompanying
+//# Everyone is permitted to copy and distribute verbatim copies
+//# of this license document, but changing it is not allowed.
+//#
+
+#ifndef QML_QT6_DEPLY_H
+#define QML_QT6_DEPLY_H
+
+#include <QSet>
+#include <QStringList>
+#include "iqml.h"
+
+class DEPLOYSHARED_EXPORT QMLQt6: public iQML {
+
+public:
+    QMLQt6(const QString& qmlRoot);
+    ~QMLQt6() override;
+
+    bool scan(QStringList &res, const QString &_qmlProjectDir) override;
+
+
+private:
+
+    QStringList extractImportsFromFile(const QString &filepath) const;
+
+    bool extractImportsFromDir(const QString &path, bool recursive = false);
+
+    QString getPathFromImport(const QString& import, bool checkVersions = true);
+
+    bool deployPath( const QString& path, QStringList& res);
+    bool scanQmlTree(const QString& qmlTree);
+    QStringList extractImportsFromQmlModule(const QString& module) const;
+    QStringList extractImportLine(const QString &line) const;
+    
+    QSet<QString> _imports;
+    QSet<QString> secondVersions;
+
+    friend class deploytest;
+    friend class QmlScanerTest;
+    friend class QMLExtractTest;
+};
+
+#endif // QML_QT6_DEPLY_H
diff --git a/tests/units/linux/qmlextracttest.cpp b/tests/units/linux/qmlextracttest.cpp
index 3023f5f..b20f9d1 100644
--- a/tests/units/linux/qmlextracttest.cpp
+++ b/tests/units/linux/qmlextracttest.cpp
@@ -7,7 +7,7 @@
 
 
 #include "qmlextracttest.h"
-#include "qml.h"
+#include "qmlqt5.h"
 #include "qmlcreator.h"
 #include <configparser.h>
 #include <dependenciesscanner.h>
@@ -23,7 +23,7 @@ void QMLExtractTest::test() {
     auto qmlFiles = creator.getCopyedQml();
 
 
-    QML scaner("./", QtMajorVersion::Qt5);
+    QMLQt5 scaner("./");
 
 
     for (const auto &file : qAsConst(qmlFiles)) {
diff --git a/tests/units/linux/qmlscanertest.cpp b/tests/units/linux/qmlscanertest.cpp
index 80a4ed4..780a576 100644
--- a/tests/units/linux/qmlscanertest.cpp
+++ b/tests/units/linux/qmlscanertest.cpp
@@ -7,7 +7,7 @@
 
 
 #include "qmlscanertest.h"
-#include "qml.h"
+#include "qmlqt6.h"
 #include <configparser.h>
 #include <dependenciesscanner.h>
 #include <filemanager.h>
@@ -18,80 +18,36 @@
 void QmlScanerTest::test() {
     // qt5
     auto qmlRoot = QFileInfo(TestQtDir + "/qml").absoluteFilePath();
-    QML *scaner = new QML(qmlRoot, QtMajorVersion::Qt5);
-    auto imports = scaner->extractImportsFromFile(":/qmlFile.qml");
-    scaner->scanQmlTree(qmlRoot);
-
-        QSet<QString> results = {
-                                 {qmlRoot + "/QtQuick.2/"},
-                                 {qmlRoot + "/QtQuick/Controls.2/"},
-                                 {qmlRoot + "/QtQuick/Controls.2/Material/"},
-                                 {qmlRoot + "/QtQuick/Layouts/"},
-                                 };
-
-    QVERIFY(results.size() == imports.size());
-
-#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
-
-    for (const auto &import: qAsConst(imports)) {
-        auto path = scaner->getPathFromImport(import);
-        QVERIFY(results.contains(path));
-    }
-#endif
+    QMLQt6 scaner6(qmlRoot);
 
     // qt6
-    scaner->setQtVersion(QtMajorVersion::Qt6);
 
-    results = {
+    QSet<QString> results = {
         {qmlRoot + "/QtQuick"},
         {qmlRoot + "/QtQuick/Controls"},
         {qmlRoot + "/QtQuick/Controls/Material"},
         {qmlRoot + "/QtQuick/Layouts"},
     };
 
-    imports = scaner->extractImportsFromFile(":/qmlFileQt6.qml");
+    auto imports = scaner6.extractImportsFromFile(":/qmlFileQt6.qml");
 
     QVERIFY(results.size() == imports.size());
 
     for (const auto &import: qAsConst(imports)) {
-        auto path = scaner->getPathFromImport(import);
+        auto path = scaner6.getPathFromImport(import);
         QVERIFY(results.contains(path));
     }
 
-    imports = scaner->extractImportsFromFile(":/qmlFile.qml");
+    imports = scaner6.extractImportsFromFile(":/qmlFile.qml");
 
     QVERIFY(results.size() == imports.size());
 
     for (const auto & import: qAsConst(imports)) {
-        auto path = scaner->getPathFromImport(import);
+        auto path = scaner6.getPathFromImport(import);
         QVERIFY(results.contains(path));
     }
 
-#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
-
-    // qt5
-    scaner->setQtVersion(QtMajorVersion::Qt5);
-
-    results = {
-        {qmlRoot + "/QtQuick.2/"},
-        {qmlRoot + "/QtQuick/Window.2/"},
-        {qmlRoot + "/QtQuick/Layouts/"},
-        {qmlRoot + "/Qt/labs/folderlistmodel/"},
-        {qmlRoot + "/QtQuick/VirtualKeyboard/Settings/"},
-        {qmlRoot + "/QtQuick/VirtualKeyboard/Styles/"},
-    };
-
-    imports = scaner->extractImportsFromQmlModule(":/qmlDir");
-
-    QVERIFY(results.size() == imports.size());
-
-    for (const auto &import: qAsConst(imports)) {
-        auto path = scaner->getPathFromImport(import);
-        QVERIFY(results.contains(path));
-    }
-#endif
     // qt6
-    scaner->setQtVersion(QtMajorVersion::Qt6);
 
     results = {
         {qmlRoot + "/QtQuick"},
@@ -102,12 +58,12 @@ void QmlScanerTest::test() {
         {qmlRoot + "/QtQuick/VirtualKeyboard/Styles"},
     };
 
-    imports = scaner->extractImportsFromQmlModule(":/qmlDir");
+    imports = scaner6.extractImportsFromQmlModule(":/qmlDir");
 
     QVERIFY(results.size() == imports.size());
 
     for (const auto &import: qAsConst(imports)) {
-        auto path = scaner->getPathFromImport(import);
+        auto path = scaner6.getPathFromImport(import);
         QVERIFY(results.contains(path));
     }
 

From 7ed0ca69ca6c377ae8c1911ef70ac382e3689570 Mon Sep 17 00:00:00 2001
From: EndrII <EndrIIMail@gmail.com>
Date: Wed, 26 Oct 2022 23:50:04 +0300
Subject: [PATCH 4/5] use old method of parsin qml of qt5

---
 src/Deploy/src/extracter.cpp | 44 +++++++++++++++++++++++-------------
 1 file changed, 28 insertions(+), 16 deletions(-)

diff --git a/src/Deploy/src/extracter.cpp b/src/Deploy/src/extracter.cpp
index 4ae4206..4c926dc 100644
--- a/src/Deploy/src/extracter.cpp
+++ b/src/Deploy/src/extracter.cpp
@@ -448,6 +448,8 @@ bool Extracter::extractQml() {
 
             QStringList plugins;
             QStringList listItems;
+            auto QtVersion = cnf->isNeededQt(i.key());
+
             const auto qmlInputList = distro.qmlInput();
             for (const auto &qmlInput: qmlInputList) {
                 QFileInfo info(qmlInput);
@@ -465,7 +467,6 @@ bool Extracter::extractQml() {
                     continue;
                 }
 
-                auto QtVersion = cnf->isNeededQt(i.key());
                 QSharedPointer<iQML> qmlScaner;
                 if (QtVersion & QtMajorVersion::Qt6) {
                     qmlScaner = QSharedPointer<QMLQt6>::create(cnf->qtDir.getQmls());
@@ -481,25 +482,36 @@ bool Extracter::extractQml() {
 
             }
 
-
             QStringList toCopyQmlFiles;
-            for (const auto& plugin: qAsConst(plugins)) {
-                const auto qmlFiles = QDir(plugin).entryInfoList(QDir::Files);
-                for (const auto& qmlFile: qmlFiles) {
-                    toCopyQmlFiles.push_back(qmlFile.absoluteFilePath());
+            if (QtVersion & QtMajorVersion::Qt5) {
+                // See the https://github.com/QuasarApp/CQtDeployer/issues/728 issue
+                // use old method of parse qml for qt5
+                if (!_fileManager->copyFolder(cnf->qtDir.getQmls(),
+                                              targetPath + distro.getQmlOutDir(),
+                                              DeployCore::debugExtensions() ,
+                                              &listItems)) {
+                    return false;
+                }
+            } else {
+                for (const auto& plugin: qAsConst(plugins)) {
+                    const auto qmlFiles = QDir(plugin).entryInfoList(QDir::Files);
+                    for (const auto& qmlFile: qmlFiles) {
+                        toCopyQmlFiles.push_back(qmlFile.absoluteFilePath());
+                    }
+                }
+
+                // This function works very slow because use list mask
+                // solution: use the QSet and restriction comparese of the pathes for the mask argument.
+                // to-do optimise this function
+                if (!_fileManager->copyFolder(cnf->qtDir.getQmls(),
+                                              targetPath + distro.getQmlOutDir(),
+                                              DeployCore::debugExtensions() ,
+                                              &listItems,
+                                              &toCopyQmlFiles)) {
+                    return false;
                 }
             }
 
-            // This function works very slow because use list mask
-            // solution: use the QSet and restriction comparese of the pathes for the mask argument.
-            // to-do optimise this function
-            if (!_fileManager->copyFolder(cnf->qtDir.getQmls(),
-                                          targetPath + distro.getQmlOutDir(),
-                                          DeployCore::debugExtensions() ,
-                                          &listItems,
-                                          &toCopyQmlFiles)) {
-                return false;
-            }
 
             for (const auto &item : qAsConst(listItems)) {
                 extractPluginLib(item, i.key());

From f0cd2c42b101ad8bb2a873dbd3d0149a3a9aa52e Mon Sep 17 00:00:00 2001
From: EndrII <EndrIIMail@gmail.com>
Date: Fri, 28 Oct 2022 12:05:29 +0300
Subject: [PATCH 5/5] fix arguments list of copy qml

---
 src/Deploy/src/extracter.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/Deploy/src/extracter.cpp b/src/Deploy/src/extracter.cpp
index 4c926dc..e179b88 100644
--- a/src/Deploy/src/extracter.cpp
+++ b/src/Deploy/src/extracter.cpp
@@ -489,7 +489,7 @@ bool Extracter::extractQml() {
                 if (!_fileManager->copyFolder(cnf->qtDir.getQmls(),
                                               targetPath + distro.getQmlOutDir(),
                                               DeployCore::debugExtensions() ,
-                                              &listItems)) {
+                                              &listItems, &plugins)) {
                     return false;
                 }
             } else {