diff --git a/CMakeLists.txt b/CMakeLists.txt index 376a7e0..fe5caf6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -60,7 +60,6 @@ endif() add_subdirectory(src) set(CRATE liblumina) - # Corrosion creates a CMake target with the same name as the crate. corrosion_import_crate(MANIFEST_PATH Cargo.toml CRATES ${CRATE}) @@ -75,33 +74,35 @@ corrosion_set_env_vars(${CRATE} "QMAKE=${QMAKE}" ) +add_library(${APP_NAME}_lib INTERFACE) # Include the headers generated by the Rust library's build script. Each # crate gets its own subdirectory under CXXQT_EXPORT_DIR. This allows you # to include headers generated by multiple crates without risk of one crate # overwriting another's files. -target_include_directories(${CRATE} INTERFACE "${CXXQT_EXPORT_DIR}/${CRATE}") +target_include_directories(${APP_NAME}_lib INTERFACE "${CXXQT_EXPORT_DIR}/${CRATE}") # Link the Rust INTERFACE library target to Qt. Do this on the library target # rather than the main executable. This way, CMake targets besides the main # executable which link the Rust library, for example tests, will also link Qt. -target_link_libraries(${CRATE} INTERFACE - Qt5::Quick - Qt5::Qml - Qt5::Gui - Qt5::QuickControls2 - Qt5::Widgets - Qt5::Sql - Qt5::X11Extras - Qt5::WebEngine - KF5::Kirigami2 - KF5::I18n - KF5::Archive - KF5::CoreAddons - mpv +target_link_libraries(${APP_NAME}_lib INTERFACE + "$" + Qt5::Quick + Qt5::Qml + Qt5::Gui + Qt5::QuickControls2 + Qt5::Widgets + Qt5::Sql + Qt5::X11Extras + Qt5::WebEngine + KF5::Kirigami2 + KF5::I18n + KF5::Archive + KF5::CoreAddons + mpv ) # Link to the Rust library -target_link_libraries(${APP_NAME} PRIVATE ${CRATE}) +target_link_libraries(${APP_NAME} PRIVATE ${APP_NAME}_lib) # If we are using a statically linked Qt then we need to import any qml plugins qt_import_qml_plugins(${APP_NAME}) diff --git a/TODO.org b/TODO.org index edf8d95..24bc02d 100644 --- a/TODO.org +++ b/TODO.org @@ -5,17 +5,21 @@ :END: * Tasks [0%] [0/0] -** TODO Port to CXX-QT 6.0 [37%] [3/8] +** TODO Port to CXX-QT 6.0 [90%] [9/10] [[file:~/dev/lumina/src/rust/lib.rs]] *** DONE image_model.rs *** DONE video_model.rs *** DONE presentation_model.rs -*** TODO songs/song_model.rs -*** TODO songs/song_editor.rs -*** TODO ytdl.rs -*** TODO utils.rs -*** TODO obs.rs +*** DONE songs/song_model.rs +*** DONE songs/song_editor.rs +*** DONE ytdl.rs +*** DONE utils.rs +*** DONE obs.rs +*** DONE 18000 errors..... +round 1 of errors done..... +*** TODO 237 errors... +now round 2 ** TODO Write a function to handle switching to the next fragment in revealjs [[file:~/dev/lumina/src/qml/presenter/Slide.qml::WebEngineView {]] diff --git a/flake.lock b/flake.lock index 9b201d3..58aa8a8 100644 --- a/flake.lock +++ b/flake.lock @@ -38,11 +38,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1699343069, - "narHash": "sha256-s7BBhyLA6MI6FuJgs4F/SgpntHBzz40/qV0xLPW6A1Q=", + "lastModified": 1701040486, + "narHash": "sha256-vawYwoHA5CwvjfqaT3A5CT9V36Eq43gxdwpux32Qkjw=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "ec750fd01963ab6b20ee1f0cb488754e8036d89d", + "rev": "45827faa2132b8eade424f6bdd48d8828754341a", "type": "github" }, "original": { @@ -52,11 +52,11 @@ }, "nixpkgs_2": { "locked": { - "lastModified": 1699099776, - "narHash": "sha256-X09iKJ27mGsGambGfkKzqvw5esP1L/Rf8H3u3fCqIiU=", + "lastModified": 1700794826, + "narHash": "sha256-RyJTnTNKhO0yqRpDISk03I/4A67/dp96YRxc86YOPgU=", "owner": "nixos", "repo": "nixpkgs", - "rev": "85f1ba3e51676fa8cc604a3d863d729026a6b8eb", + "rev": "5a09cb4b393d58f9ed0d9ca1555016a8543c2ac8", "type": "github" }, "original": { diff --git a/justfile b/justfile index 0f28ba4..aa85966 100644 --- a/justfile +++ b/justfile @@ -8,3 +8,6 @@ run: RUST_LOG=debug ./bld/bin/lumina lint: cargo clippy +clean: + cargo clean + rm -rf bld/ \ No newline at end of file diff --git a/src/cpp/serviceitemmodel.cpp b/src/cpp/serviceitemmodel.cpp index 6886a15..0ebc600 100644 --- a/src/cpp/serviceitemmodel.cpp +++ b/src/cpp/serviceitemmodel.cpp @@ -27,11 +27,11 @@ #include "cxx-qt-gen/slide_model.cxxqt.h" #include "cxx-qt-gen/service_item_model.cxxqt.h" -ServiceItemModel::ServiceItemModel(QObject *parent) +ServiceItemModelCpp::ServiceItemModelCpp(QObject *parent) : QAbstractListModel(parent) { } -int ServiceItemModel::rowCount(const QModelIndex &parent) const { +int ServiceItemModelCpp::rowCount(const QModelIndex &parent) const { // For list models only the root node (an invalid parent) should return the // list's size. For all other (valid) parents, rowCount() should return 0 so // that it does not become a tree model. @@ -42,7 +42,7 @@ int ServiceItemModel::rowCount(const QModelIndex &parent) const { return m_items.size(); } -QVariant ServiceItemModel::data(const QModelIndex &index, int role) const { +QVariant ServiceItemModelCpp::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); @@ -77,7 +77,7 @@ QVariant ServiceItemModel::data(const QModelIndex &index, int role) const { } } -QHash ServiceItemModel::roleNames() const { +QHash ServiceItemModelCpp::roleNames() const { static QHash mapping{{NameRole, "name"}, {TypeRole, "type"}, {BackgroundRole, "background"}, @@ -94,7 +94,7 @@ QHash ServiceItemModel::roleNames() const { return mapping; } -bool ServiceItemModel::setData(const QModelIndex &index, const QVariant &value, +bool ServiceItemModelCpp::setData(const QModelIndex &index, const QVariant &value, int role) { ServiceItem *item = m_items[index.row()]; @@ -182,14 +182,14 @@ bool ServiceItemModel::setData(const QModelIndex &index, const QVariant &value, return false; } -Qt::ItemFlags ServiceItemModel::flags(const QModelIndex &index) const { +Qt::ItemFlags ServiceItemModelCpp::flags(const QModelIndex &index) const { if (!index.isValid()) return Qt::NoItemFlags; return Qt::ItemIsEditable; // FIXME: Implement me! } -void ServiceItemModel::addItem(ServiceItem *item) { +void ServiceItemModelCpp::addItem(ServiceItem *item) { const int index = m_items.size(); qDebug() << index; // foreach (item, m_items) { @@ -200,14 +200,14 @@ void ServiceItemModel::addItem(ServiceItem *item) { endInsertRows(); } -void ServiceItemModel::insertItem(const int &index, ServiceItem *item) { +void ServiceItemModelCpp::insertItem(const int &index, ServiceItem *item) { beginInsertRows(this->index(index).parent(), index, index); m_items.insert(index, item); endInsertRows(); qDebug() << "Success"; } -void ServiceItemModel::addItem(const QString &name, const QString &type, +void ServiceItemModelCpp::addItem(const QString &name, const QString &type, const QString &background, const QString &backgroundType, const QStringList &text, const QString &audio, const QString &font, const int &fontSize, @@ -248,7 +248,7 @@ void ServiceItemModel::addItem(const QString &name, const QString &type, qDebug() << "#################################"; } -void ServiceItemModel::insertItem(const int &index, const QString &name, +void ServiceItemModelCpp::insertItem(const int &index, const QString &name, const QString &type,const QString &background, const QString &backgroundType,const QStringList &text, const QString &audio, const QString &font, @@ -289,13 +289,13 @@ void ServiceItemModel::insertItem(const int &index, const QString &name, qDebug() << "#################################"; } -void ServiceItemModel::removeItem(int index) { +void ServiceItemModelCpp::removeItem(int index) { beginRemoveRows(QModelIndex(), index, index); m_items.removeAt(index); endRemoveRows(); } -void ServiceItemModel::removeItems() { +void ServiceItemModelCpp::removeItems() { for (int i = m_items.length() - 1; i > -1; i--) { QModelIndex idx = index(i); ServiceItem *item = m_items[idx.row()]; @@ -313,7 +313,7 @@ void ServiceItemModel::removeItems() { } -bool ServiceItemModel::moveRows(int sourceIndex, int destIndex, int count) { +bool ServiceItemModelCpp::moveRows(int sourceIndex, int destIndex, int count) { qDebug() << sourceIndex; qDebug() << destIndex; @@ -349,7 +349,7 @@ bool ServiceItemModel::moveRows(int sourceIndex, int destIndex, int count) { return true; } -bool ServiceItemModel::moveDown(int id) { +bool ServiceItemModelCpp::moveDown(int id) { qDebug() << index(id).row(); qDebug() << index(id + 1).row(); QModelIndex parent = index(id).parent(); @@ -371,7 +371,7 @@ bool ServiceItemModel::moveDown(int id) { return false; } -bool ServiceItemModel::moveUp(int id) { +bool ServiceItemModelCpp::moveUp(int id) { qDebug() << index(id).row(); qDebug() << index(id - 1).row(); QModelIndex parent = index(id).parent(); @@ -394,7 +394,7 @@ bool ServiceItemModel::moveUp(int id) { return false; } -bool ServiceItemModel::moveRowsRust(int source, int dest, int count, ServiceItemMod *rustModel) { +bool ServiceItemModelCpp::moveRowsRust(int source, int dest, int count, ServiceItemModel *rustModel) { const QModelIndex parent = index(source).parent(); const bool isMoveDown = dest > source; @@ -409,12 +409,12 @@ bool ServiceItemModel::moveRowsRust(int source, int dest, int count, ServiceItem return moved; } -QVariantMap ServiceItemModel::getRust(int index, ServiceItemMod *rustModel) const { +QVariantMap ServiceItemModelCpp::getRust(int index, ServiceItemModel *rustModel) const { QVariantMap item = rustModel->getItem(index); return item; } -QVariantMap ServiceItemModel::getItem(int index) const { +QVariantMap ServiceItemModelCpp::getItem(int index) const { QVariantMap data; const QModelIndex idx = this->index(index,0); // qDebug() << idx; @@ -431,7 +431,7 @@ QVariantMap ServiceItemModel::getItem(int index) const { return data; } -QVariantList ServiceItemModel::getItems() { +QVariantList ServiceItemModelCpp::getItems() { QVariantList data; ServiceItem * item; foreach (item, m_items) { @@ -457,7 +457,7 @@ QVariantList ServiceItemModel::getItems() { return data; } -bool ServiceItemModel::select(int id) { +bool ServiceItemModelCpp::select(int id) { for (int i = 0; i < m_items.length(); i++) { QModelIndex idx = index(i); ServiceItem *item = m_items[idx.row()]; @@ -479,7 +479,7 @@ bool ServiceItemModel::select(int id) { return true; } -bool ServiceItemModel::selectItems(QVariantList items) { +bool ServiceItemModelCpp::selectItems(QVariantList items) { qDebug() << "Let's select some items!"; for (int i = 0; i < m_items.length(); i++) { QModelIndex idx = index(i); @@ -508,7 +508,7 @@ bool ServiceItemModel::selectItems(QVariantList items) { return true; } -bool ServiceItemModel::activate(int id) { +bool ServiceItemModelCpp::activate(int id) { QModelIndex idx = index(id); ServiceItem *item = m_items[idx.row()]; @@ -532,7 +532,7 @@ bool ServiceItemModel::activate(int id) { return true; } -bool ServiceItemModel::deactivate(int id) { +bool ServiceItemModelCpp::deactivate(int id) { QModelIndex idx = index(id); ServiceItem *item = m_items[idx.row()]; @@ -544,7 +544,7 @@ bool ServiceItemModel::deactivate(int id) { return true; } -bool ServiceItemModel::save(QUrl file) { +bool ServiceItemModelCpp::save(QUrl file) { qDebug() << "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"; qDebug() << "Saving..."; qDebug() << "File path is: " << file.toString(); @@ -661,7 +661,7 @@ bool ServiceItemModel::save(QUrl file) { return false; } -bool ServiceItemModel::load(QUrl file) { +bool ServiceItemModelCpp::load(QUrl file) { qDebug() << "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"; qDebug() << "Loading..."; qDebug() << "File path is: " << file.toString(); @@ -780,14 +780,14 @@ bool ServiceItemModel::load(QUrl file) { return false; } -void ServiceItemModel::clearAll() { +void ServiceItemModelCpp::clearAll() { for (int i = m_items.size(); i >= 0; i--) { removeItem(i); } emit allRemoved(); } -bool ServiceItemModel::loadLastSaved() { +bool ServiceItemModelCpp::loadLastSaved() { QSettings settings; return load(settings.value("lastSaveFile").toUrl()); } diff --git a/src/cpp/serviceitemmodel.h b/src/cpp/serviceitemmodel.h index dd9b9b5..0318018 100644 --- a/src/cpp/serviceitemmodel.h +++ b/src/cpp/serviceitemmodel.h @@ -11,11 +11,11 @@ #include "cxx-qt-gen/service_item_model.cxxqt.h" -class ServiceItemModel : public QAbstractListModel { +class ServiceItemModelCpp : public QAbstractListModel { Q_OBJECT public: - explicit ServiceItemModel(QObject *parent = nullptr); + explicit ServiceItemModelCpp(QObject *parent = nullptr); enum Roles { NameRole = Qt::UserRole, @@ -66,7 +66,7 @@ public: Q_INVOKABLE void removeItem(int index); Q_INVOKABLE void removeItems(); Q_INVOKABLE bool moveRows(int sourceIndex, int destIndex, int count); - Q_INVOKABLE bool moveRowsRust(int source, int dest, int count, ServiceItemMod *rustModel); + Q_INVOKABLE bool moveRowsRust(int source, int dest, int count, ServiceItemModel *rustModel); Q_INVOKABLE bool moveDown(int index); Q_INVOKABLE bool moveUp(int index); Q_INVOKABLE bool select(int id); @@ -74,7 +74,7 @@ public: Q_INVOKABLE bool activate(int id); Q_INVOKABLE bool deactivate(int id); Q_INVOKABLE QVariantMap getItem(int index) const; - Q_INVOKABLE QVariantMap getRust(int index, ServiceItemMod *rustModel) const; + Q_INVOKABLE QVariantMap getRust(int index, ServiceItemModel *rustModel) const; Q_INVOKABLE QVariantList getItems(); Q_INVOKABLE void clearAll(); diff --git a/src/cpp/slidemodel.cpp b/src/cpp/slidemodel.cpp index e11cca0..6ffdc90 100644 --- a/src/cpp/slidemodel.cpp +++ b/src/cpp/slidemodel.cpp @@ -27,7 +27,7 @@ const QDir writeDir = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); -SlideModel::SlideModel(QObject *parent) +SlideModelCpp::SlideModelCpp(QObject *parent) : QAbstractListModel(parent) { // if () { // addItem(new Slide("10,000 Reasons", "song", @@ -43,7 +43,7 @@ SlideModel::SlideModel(QObject *parent) // } } -int SlideModel::rowCount(const QModelIndex &parent) const { +int SlideModelCpp::rowCount(const QModelIndex &parent) const { // For list models only the root node (an invalid parent) should return the // list's size. For all other (valid) parents, rowCount() should return 0 so // that it does not become a tree model. @@ -54,7 +54,7 @@ int SlideModel::rowCount(const QModelIndex &parent) const { return m_items.size(); } -QVariant SlideModel::data(const QModelIndex &index, int role) const { +QVariant SlideModelCpp::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); @@ -95,7 +95,7 @@ QVariant SlideModel::data(const QModelIndex &index, int role) const { } } -QHash SlideModel::roleNames() const { +QHash SlideModelCpp::roleNames() const { static QHash mapping { {TextRole, "text"}, {TypeRole, "type"}, @@ -117,7 +117,7 @@ QHash SlideModel::roleNames() const { return mapping; } -bool SlideModel::setData(const QModelIndex &index, const QVariant &value, +bool SlideModelCpp::setData(const QModelIndex &index, const QVariant &value, int role) { Slide *item = m_items[index.row()]; @@ -223,14 +223,14 @@ bool SlideModel::setData(const QModelIndex &index, const QVariant &value, return false; } -Qt::ItemFlags SlideModel::flags(const QModelIndex &index) const { +Qt::ItemFlags SlideModelCpp::flags(const QModelIndex &index) const { if (!index.isValid()) return Qt::NoItemFlags; return Qt::ItemIsEditable; // FIXME: Implement me! } -// int SlideModel::index(int row, int column, const QModelIndex &parent) { +// int SlideyMod::index(int row, int column, const QModelIndex &parent) { // if (!hasIndex(row, column, parent)) // return QModelIndex(); @@ -247,7 +247,7 @@ Qt::ItemFlags SlideModel::flags(const QModelIndex &index) const { // return QModelIndex(); // } -void SlideModel::addItem(Slide *item) { +void SlideModelCpp::addItem(Slide *item) { const int index = m_items.size(); qDebug() << index; // foreach (item, m_items) { @@ -258,14 +258,14 @@ void SlideModel::addItem(Slide *item) { endInsertRows(); } -void SlideModel::insertItem(const int &index, Slide *item) { +void SlideModelCpp::insertItem(const int &index, Slide *item) { beginInsertRows(this->index(index).parent(), index, index); m_items.insert(index, item); endInsertRows(); qDebug() << "Success"; } -void SlideModel::addItem(const QString &text, const QString &type, +void SlideModelCpp::addItem(const QString &text, const QString &type, const QString &imageBackground, const QString &videoBackground, const QString &audio, const QString &font, const int &fontSize, @@ -286,7 +286,7 @@ void SlideModel::addItem(const QString &text, const QString &type, qDebug() << "#################################"; } -void SlideModel::insertItem(const int &index, +void SlideModelCpp::insertItem(const int &index, const QString &type, const QString &imageBackground, const QString &videoBackground, const QString &text, const QString &audio, const QString &font, @@ -307,13 +307,13 @@ void SlideModel::insertItem(const int &index, qDebug() << "#################################"; } -void SlideModel::removeItem(int index) { +void SlideModelCpp::removeItem(int index) { beginRemoveRows(QModelIndex(), index, index); m_items.removeAt(index); endRemoveRows(); } -void SlideModel::removeServiceItem(const int &index, const ServiceItem &item) { +void SlideModelCpp::removeServiceItem(const int &index, const ServiceItem &item) { qDebug() << "Need to remove serviceItem:" << item.name() << "with" @@ -345,7 +345,7 @@ void SlideModel::removeServiceItem(const int &index, const ServiceItem &item) { } } -void SlideModel::removeItems() { +void SlideModelCpp::removeItems() { for (int i = m_items.length() - 1; i > -1; i--) { QModelIndex idx = index(i); Slide *item = m_items[idx.row()]; @@ -358,7 +358,7 @@ void SlideModel::removeItems() { } } -bool SlideModel::moveRows(int sourceIndex, int destIndex, int count) { +bool SlideModelCpp::moveRows(int sourceIndex, int destIndex, int count) { qDebug() << index(sourceIndex).row(); qDebug() << index(destIndex).row(); @@ -391,7 +391,7 @@ bool SlideModel::moveRows(int sourceIndex, int destIndex, int count) { return true; } -bool SlideModel::moveDown(int id) { +bool SlideModelCpp::moveDown(int id) { qDebug() << index(id).row(); qDebug() << index(id + 1).row(); QModelIndex parent = index(id).parent(); @@ -413,7 +413,7 @@ bool SlideModel::moveDown(int id) { return false; } -bool SlideModel::moveUp(int id) { +bool SlideModelCpp::moveUp(int id) { qDebug() << index(id).row(); qDebug() << index(id - 1).row(); QModelIndex parent = index(id).parent(); @@ -436,7 +436,7 @@ bool SlideModel::moveUp(int id) { return false; } -QVariantMap SlideModel::getItem(int index) const { +QVariantMap SlideModelCpp::getItem(int index) const { QVariantMap data; const QModelIndex idx = this->index(index,0); // qDebug() << idx; @@ -453,13 +453,13 @@ QVariantMap SlideModel::getItem(int index) const { return data; } -QVariantMap SlideModel::getItemRust(int index, SlideyMod *slidemodel) const { +QVariantMap SlideModelCpp::getItemRust(int index, SlideModel *slidemodel) const { QVariantMap data = slidemodel->getItem(index); qDebug() << data; return data; } -QVariantList SlideModel::getItems() { +QVariantList SlideModelCpp::getItems() { QVariantList data; Slide * item; foreach (item, m_items) { @@ -486,7 +486,7 @@ QVariantList SlideModel::getItems() { return data; } -bool SlideModel::select(int id) { +bool SlideModelCpp::select(int id) { for (int i = 0; i < m_items.length(); i++) { QModelIndex idx = index(i); Slide *item = m_items[idx.row()]; @@ -508,7 +508,7 @@ bool SlideModel::select(int id) { return true; } -bool SlideModel::activate(int id) { +bool SlideModelCpp::activate(int id) { QModelIndex idx = index(id); Slide *item = m_items[idx.row()]; qDebug() << item->type(); @@ -534,7 +534,7 @@ bool SlideModel::activate(int id) { return true; } -bool SlideModel::deactivate(int id) { +bool SlideModelCpp::deactivate(int id) { QModelIndex idx = index(id); Slide *item = m_items[idx.row()]; @@ -546,13 +546,13 @@ bool SlideModel::deactivate(int id) { return true; } -void SlideModel::clearAll() { +void SlideModelCpp::clearAll() { for (int i = m_items.size(); i >= 0; i--) { removeItem(i); } } -int SlideModel::findSlideIdFromServItm(int index) { +int SlideModelCpp::findSlideIdFromServItm(int index) { for (int i = 0; i < m_items.size(); i++) { Slide *itm = m_items[i]; if (itm->serviceItemId() == index) { @@ -562,7 +562,7 @@ int SlideModel::findSlideIdFromServItm(int index) { return 0; } -void SlideModel::addItemFromService(const int &index, const ServiceItem &item) { +void SlideModelCpp::addItemFromService(const int &index, const ServiceItem &item) { qDebug() << "***INSERTING SLIDE FROM SERVICEITEM***"; if (item.type() == "song") { for (int i = 0; i < item.text().size(); i++) { @@ -597,7 +597,7 @@ void SlideModel::addItemFromService(const int &index, const ServiceItem &item) { } -void SlideModel::insertItemFromService(const int &index, const ServiceItem &item) { +void SlideModelCpp::insertItemFromService(const int &index, const ServiceItem &item) { qDebug() << "***INSERTING SLIDE FROM SERVICEITEM***"; int slideId = findSlideIdFromServItm(index); // move all slides to the next serviceItem @@ -640,7 +640,7 @@ void SlideModel::insertItemFromService(const int &index, const ServiceItem &item } -void SlideModel::moveRowFromService(const int &fromIndex, +void SlideModelCpp::moveRowFromService(const int &fromIndex, const int &toIndex, const ServiceItem &item) { const bool isMoveDown = toIndex > fromIndex; @@ -700,7 +700,7 @@ void SlideModel::moveRowFromService(const int &fromIndex, } } -QString SlideModel::thumbnailVideoRust(QString video, int serviceItemId, int index, SlideyMod *slideModel) { +QString SlideModelCpp::thumbnailVideoRust(QString video, int serviceItemId, int index, SlideModel *slideModel) { QDir dir = writeDir.absolutePath() + "/librepresenter/thumbnails"; QDir absDir = writeDir.absolutePath() + "/librepresenter"; @@ -745,7 +745,7 @@ QString SlideModel::thumbnailVideoRust(QString video, int serviceItemId, int ind return thumbnailInfo.filePath(); } -QString SlideModel::thumbnailVideo(QString video, int serviceItemId, int index) { +QString SlideModelCpp::thumbnailVideo(QString video, int serviceItemId, int index) { QDir dir = writeDir.absolutePath() + "/librepresenter/thumbnails"; QDir absDir = writeDir.absolutePath() + "/librepresenter"; @@ -803,7 +803,7 @@ QString SlideModel::thumbnailVideo(QString video, int serviceItemId, int index) return thumbnailInfo.filePath(); } -QImage SlideModel::frameToImage(const QString &video, int width) +QImage SlideModelCpp::frameToImage(const QString &video, int width) { QImage image; FrameDecoder frameDecoder(video, nullptr); diff --git a/src/cpp/slidemodel.h b/src/cpp/slidemodel.h index b0c8889..025d341 100644 --- a/src/cpp/slidemodel.h +++ b/src/cpp/slidemodel.h @@ -10,11 +10,11 @@ #include #include "cxx-qt-gen/slide_model.cxxqt.h" -class SlideModel : public QAbstractListModel { +class SlideModelCpp : public QAbstractListModel { Q_OBJECT public: - explicit SlideModel(QObject *parent = nullptr); + explicit SlideModelCpp(QObject *parent = nullptr); enum Roles { TypeRole = Qt::UserRole, @@ -82,11 +82,11 @@ public: Q_INVOKABLE bool moveDown(int index); Q_INVOKABLE bool moveUp(int index); Q_INVOKABLE QVariantMap getItem(int index) const; - Q_INVOKABLE QVariantMap getItemRust(int index, SlideyMod *slidemodel) const; + Q_INVOKABLE QVariantMap getItemRust(int index, SlideModel *slidemodel) const; Q_INVOKABLE QVariantList getItems(); Q_INVOKABLE int findSlideIdFromServItm(int index); Q_INVOKABLE QString thumbnailVideo(QString video, int serviceItemId, int index); - Q_INVOKABLE QString thumbnailVideoRust(QString video, int serviceItemId, int index, SlideyMod *slideModel); + Q_INVOKABLE QString thumbnailVideoRust(QString video, int serviceItemId, int index, SlideModel *slideModel); QImage frameToImage(const QString &video, int width); diff --git a/src/main.cpp b/src/main.cpp index 1e3a76b..9317938 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -140,19 +140,14 @@ int main(int argc, char *argv[]) qDebug() << QIcon::themeName(); qDebug() << QApplication::platformName(); - // integrate with commandline argument handling - // QCommandLineParser parser; - // aboutData.setupCommandLine(&parser); - // setup of app specific commandline args - //Need to instantiate our slide QScopedPointer utils(new Utils); QScopedPointer slideModel(new SlideModel); - QScopedPointer slideMod(new SlideyMod); + QScopedPointer slideMod(new SlideModelCpp); QScopedPointer filemanager(new File); // QScopedPointer preswin(new QQuickView); - QScopedPointer serviceItemModel(new ServiceItemMod); - QScopedPointer serviceItemC(new ServiceItemModel); + QScopedPointer serviceItemModel(new ServiceItemModel); + QScopedPointer serviceItemC(new ServiceItemModelCpp); QScopedPointer slideobject(new SlideObject); QScopedPointer obsModel(new ObsModel); obsModel.get()->getObs(); @@ -167,41 +162,42 @@ int main(int argc, char *argv[]) // PresWindow->setSource(QUrl(QStringLiteral("qrc://qml/presenter/PresentationWindow.qml"))); qDebug() << PresWindow->isVisible(); - QObject::connect(serviceItemModel.get(), + QObject::connect(serviceItemC.get(), SIGNAL(itemInserted(const int&, const ServiceItem&)), - slideModel.get(), + slideMod.get(), SLOT(insertItemFromService(const int&, const ServiceItem&))); - QObject::connect(serviceItemModel.get(), + QObject::connect(serviceItemC.get(), SIGNAL(itemAdded(const int&, const ServiceItem&)), - slideModel.get(), + slideMod.get(), SLOT(addItemFromService(const int&, const ServiceItem&))); + QObject::connect(serviceItemModel.get(), - &ServiceItemMod::itemAdded, - slideMod.get(), - &SlideyMod::addItemFromService); + &ServiceItemModel::itemAdded, + slideModel.get(), + &SlideModel::addItemFromService); QObject::connect(serviceItemModel.get(), - &ServiceItemMod::itemInserted, - slideMod.get(), - &SlideyMod::insertItemFromService); + &ServiceItemModel::itemInserted, + slideModel.get(), + &SlideModel::insertItemFromService); QObject::connect(serviceItemModel.get(), - &ServiceItemMod::itemMoved, - slideMod.get(), - &SlideyMod::moveItemFromService); + &ServiceItemModel::itemMoved, + slideModel.get(), + &SlideModel::moveItemFromService); QObject::connect(serviceItemModel.get(), - &ServiceItemMod::itemRemoved, - slideMod.get(), - &SlideyMod::removeItemFromService); + &ServiceItemModel::itemRemoved, + slideModel.get(), + &SlideModel::removeItemFromService); QObject::connect(serviceItemModel.get(), - &ServiceItemMod::cleared, - slideMod.get(), - &SlideyMod::clear); + &ServiceItemModel::cleared, + slideModel.get(), + &SlideModel::clear); // QObject::connect(serviceItemModel.get(), // SIGNAL(allRemoved()), // slideMod.get(), // SLOT(clear())); QObject::connect(slideobject.get(), SIGNAL(slideChanged(int)), - slideMod.get(), + slideModel.get(), SLOT(activate(int))); utils.get()->setup(); diff --git a/src/qml/main.qml b/src/qml/main.qml index 35465b5..2336dcc 100644 --- a/src/qml/main.qml +++ b/src/qml/main.qml @@ -121,12 +121,12 @@ Kirigami.ApplicationWindow { Controls.Label { Layout.alignment: Qt.AlignRight Layout.rightMargin: Kirigami.Units.smallSpacing * 2 - text: "Total Service Items: " + ServiceItemModel.count() + text: "Total Service Items: " + ServiceItemModel.count } Controls.Label { Layout.alignment: Qt.AlignRight Layout.rightMargin: Kirigami.Units.smallSpacing * 2 - text: "Total Slides: " + SlideMod.count() + text: "Total Slides: " + SlideModel.count } } } diff --git a/src/qml/presenter/Library.qml b/src/qml/presenter/Library.qml index 0a900a2..a380e79 100644 --- a/src/qml/presenter/Library.qml +++ b/src/qml/presenter/Library.qml @@ -40,11 +40,11 @@ Item { headerLabel: "Songs" itemIcon: "folder-music-symbolic" /* itemSubtitle: model.author */ - count: innerModel.count() + count: innerModel.count newItemFunction: (function() { songProxyModel.setFilterRegularExpression(""); innerModel.newSong(); - libraryList.currentIndex = innerModel.count() - 1; + libraryList.currentIndex = innerModel.count - 1; if (!editMode) editMode = true; editSwitch(libraryList.currentIndex, "song"); @@ -67,7 +67,7 @@ Item { headerLabel: "Videos" itemIcon: "folder-videos-symbolic" /* itemSubtitle: model.path */ - count: innerModel.count() + count: innerModel.count newItemFunction: (function() { videoProxyModel.setFilterRegularExpression(""); newVideo.open(); @@ -102,7 +102,7 @@ Item { headerLabel: "Images" itemIcon: "folder-pictures-symbolic" /* itemSubtitle: model.path */ - count: innerModel.count() + count: innerModel.count newItemFunction: (function() { imageProxyModel.setFilterRegularExpression(""); }) @@ -123,7 +123,7 @@ Item { headerLabel: "Presentations" itemIcon: "x-office-presentation-symbolic" /* itemSubtitle: model.path */ - count: innerModel.count() + count: innerModel.count newItemFunction: (function() { presProxyModel.setFilterRegularExpression(""); }) @@ -320,7 +320,7 @@ Item { function addVideo(url) { videoProxyModel.videoModel.newItem(url); selectedLibrary = "video"; - videoLibrary.libraryList.currentIndex = videoProxyModel.videoModel.count() - 1; + videoLibrary.libraryList.currentIndex = videoProxyModel.videoModel.count - 1; if (!editMode) editMode = true; editSwitch(videoLibrary.libraryList.currentIndex, "video"); @@ -329,7 +329,7 @@ Item { function addImg(url) { imageProxyModel.newItem(url); selectedLibrary = "image"; - imageLibrary.libraryList.currentIndex = imageProxyModel.imageModel.count() - 1; + imageLibrary.libraryList.currentIndex = imageProxyModel.imageModel.count - 1; if (!editMode) editMode = true; editSwitch(imageLibrary.libraryList.currentIndex, "image"); @@ -350,7 +350,7 @@ Item { presProxyModel.presentationModel.newItem(url, pageCount); selectedLibrary = "presentation"; - presentationLibrary.libraryList.currentIndex = presProxyModel.presentationModel.count() - 1; + presentationLibrary.libraryList.currentIndex = presProxyModel.presentationModel.count - 1; if (!editMode) editMode = true; editSwitch(presentationLibrary.libraryList.currentIndex, "presentation"); diff --git a/src/qml/presenter/MainWindow.qml b/src/qml/presenter/MainWindow.qml index 8c54616..087cb0c 100644 --- a/src/qml/presenter/MainWindow.qml +++ b/src/qml/presenter/MainWindow.qml @@ -15,8 +15,8 @@ Controls.Page { // properties passed around for the slides property int currentServiceItem property int currentSlide - property int totalServiceItems: ServiceItemModel.rowCount() - property int totalSlides: SlideMod.count() + property int totalServiceItems: ServiceItemModel.rowCount + property int totalSlides: SlideModel.count property url imageBackground: presentation.imageBackground property url videoBackground: presentation.vidBackground property url webSource @@ -184,9 +184,9 @@ Controls.Page { console.log("change-service-item: " + index); const item = ServiceItemC.getRust(index, ServiceItemModel); currentServiceItem = index; - const slideId = SlideMod.getSlideFromService(index); + const slideId = SlideModel.getSlideFromService(index); currentSlide = slideId; - const slide = SlideModel.getItemRust(slideId, SlideMod); + const slide = SlideMod.getItemRust(slideId, SlideModel); console.log("index grabbed: " + index); console.log(slideId); console.log("Time to start changing"); @@ -217,8 +217,8 @@ Controls.Page { function changeSlide(index) { console.log("index grabbed: " + index); - const currentItem = SlideModel.getItemRust(currentServiceItem, SlideMod); - const item = SlideModel.getItemRust(index, SlideMod); + const currentItem = SlideMod.getItemRust(currentServiceItem, SlideModel); + const item = SlideMod.getItemRust(index, SlideModel); const isMoveDown = currentSlide < index; console.log(item + " " + currentItem); currentSlide = index; @@ -250,7 +250,7 @@ Controls.Page { ServiceItemModel.activate(currentServiceItem); /* SlideObject.changeSlide(slide, slideId); */ slideHelper.chngSlide(item, index, SlideObject); - /* SlideMod.activate(index); */ + /* SlideModel.activate(index); */ presentation.textIndex = 0; console.log("Slide changed to: ", item.imageBackground); activeServiceItem = ServiceItemC.getRust(currentServiceItem, ServiceItemModel).name; diff --git a/src/qml/presenter/Presentation.qml b/src/qml/presenter/Presentation.qml index 124ac1a..7f38e1b 100644 --- a/src/qml/presenter/Presentation.qml +++ b/src/qml/presenter/Presentation.qml @@ -202,7 +202,7 @@ FocusScope { spacing: Kirigami.Units.smallSpacing * 2 cacheBuffer: 900 reuseItems: true - model: SlideMod + model: SlideModel delegate: Presenter.PreviewSlideListDelegate {} highlight: highlightBar highlightFollowsCurrentItem: false @@ -233,7 +233,7 @@ FocusScope { Connections { - target: SlideMod + target: SlideModel function onActiveChanged(index) { console.log("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$"); console.log(index); @@ -282,7 +282,7 @@ FocusScope { cacheBuffer: 800 reuseItems: true clip: true - model: SlideMod + model: SlideModel delegate: Presenter.PreviewSlideListDelegate { showVidBG: false } Kirigami.WheelHandler { @@ -355,8 +355,8 @@ FocusScope { /* target: ServiceItemModel */ /* function onActivateChanged(index) { */ /* console.log("$$$$$$$$$$$$$$$$$$$$"); */ - /* const slide = SlideModel.getSlideFromService(index); */ - /* SlideMod.activate(slide); */ + /* const slide = SlideMod.getSlideFromService(index); */ + /* SlideModel.activate(slide); */ /* } */ /* } */ diff --git a/src/qml/presenter/PreviewSlideListDelegate.qml b/src/qml/presenter/PreviewSlideListDelegate.qml index 7253c45..20c03d8 100644 --- a/src/qml/presenter/PreviewSlideListDelegate.qml +++ b/src/qml/presenter/PreviewSlideListDelegate.qml @@ -14,7 +14,7 @@ Item { /* property var previewSlidesList: parent */ /* Component.onCompleted: { */ /* if (model.videoBackground != "") */ - /* SlideModel.thumbnailVideoRust(model.videoBackground, model.serviceItemId, index, SlideMod); */ + /* SlideMod.thumbnailVideoRust(model.videoBackground, model.serviceItemId, index, SlideModel); */ /* } */ Rectangle { diff --git a/src/qml/presenter/ServiceList.qml b/src/qml/presenter/ServiceList.qml index 4e0c009..eaa9b6e 100644 --- a/src/qml/presenter/ServiceList.qml +++ b/src/qml/presenter/ServiceList.qml @@ -73,7 +73,7 @@ Item { onEntered: (drag) => { if (drag.keys[0] === "library") { dropHighlightLine.visible = true; - var lastItem = serviceItemList.itemAtIndex(ServiceItemModel.count() - 1); + var lastItem = serviceItemList.itemAtIndex(ServiceItemModel.count - 1); dropHighlightLine.y = lastItem.y + lastItem.height; } } diff --git a/src/qml/presenter/SongEditor.qml b/src/qml/presenter/SongEditor.qml index 4b3d074..ed00f6a 100644 --- a/src/qml/presenter/SongEditor.qml +++ b/src/qml/presenter/SongEditor.qml @@ -513,8 +513,8 @@ Item { } function changeSong(index) { - console.log("Preparing to change song: " + index + 1 + " out of " + songProxyModel.songModel.count()); - if (songProxyModel.songModel.count() - 1 === index) + console.log("Preparing to change song: " + index + 1 + " out of " + songProxyModel.songModel.count); + if (songProxyModel.songModel.count - 1 === index) newSong(index) else { clearSlides(); diff --git a/src/rust/file_helper.rs b/src/rust/file_helper.rs index a3bcfe7..46b10e3 100644 --- a/src/rust/file_helper.rs +++ b/src/rust/file_helper.rs @@ -36,8 +36,9 @@ mod file_helper { } } +use cxx_qt_lib::{QString, QUrl}; use rfd::FileDialog; -use std::path::Path; +use std::{path::Path, pin::Pin}; use tracing::{debug, debug_span, error, info, instrument}; #[derive(Clone)] @@ -55,7 +56,7 @@ impl Default for FileHelperRust { } } -impl qobject::FileHelper { +impl file_helper::FileHelper { pub fn load(self: Pin<&mut Self>, file: QUrl) -> Vec { println!("{file}"); vec!["hi".to_string()] diff --git a/src/rust/image_model.rs b/src/rust/image_model.rs index 873adda..75d735c 100644 --- a/src/rust/image_model.rs +++ b/src/rust/image_model.rs @@ -25,7 +25,7 @@ mod image_model { } #[qenum(ImageModel)] - enum Role { + enum ImageRoles { Id, Path, Title, @@ -35,7 +35,7 @@ mod image_model { #[qobject] #[base = "QAbstractListModel"] #[qml_element] - #[qproperty(i32, count_rows)] + #[qproperty(i32, count)] type ImageModel = super::ImageModelRust; #[inherit] @@ -151,19 +151,24 @@ mod image_model { #[cxx_override] fn row_count(self: &ImageModel, _parent: &QModelIndex) -> i32; - - #[qinvokable] - fn count(self: &ImageModel) -> i32; } } -use crate::image_model::image_model::Image; use crate::schema::images::dsl::*; +use cxx_qt::{CxxQtType, Threading}; +use cxx_qt_lib::{QModelIndex, QString, QUrl, QVariant}; use diesel::sqlite::SqliteConnection; use diesel::{delete, insert_into, prelude::*, update}; use std::path::PathBuf; +use std::pin::Pin; + +use self::image_model::{ + ImageRoles, QHash_i32_QByteArray, QMap_QString_QVariant, + QVector_i32, +}; #[derive(Default, Clone, Debug)] +/// Idk what this is but it's cool pub struct Image { id: i32, title: QString, @@ -172,16 +177,16 @@ pub struct Image { #[derive(Default, Debug)] pub struct ImageModelRust { - count_rows: i32, + count: i32, highest_id: i32, - images: Vec, + images: Vec, } -impl qobject::ImageModel { +impl image_model::ImageModel { pub fn clear(mut self: Pin<&mut Self>) { unsafe { self.as_mut().begin_reset_model(); - self.as_mut().images_mut().clear(); + self.as_mut().rust_mut().images.clear(); self.as_mut().end_reset_model(); } } @@ -191,7 +196,7 @@ impl qobject::ImageModel { let results = images .load::(db) .expect("Error loading images"); - self.as_mut().set_highest_id(0); + self.as_mut().rust_mut().highest_id = 0; println!("SHOWING IMAGES"); println!("--------------"); @@ -200,8 +205,8 @@ impl qobject::ImageModel { println!("{}", image.id); println!("{}", image.path); println!("--------------"); - if self.as_mut().highest_id() < &image.id { - self.as_mut().set_highest_id(image.id); + if &self.as_mut().highest_id < &image.id { + self.as_mut().rust_mut().highest_id = image.id; } let img = self::Image { @@ -213,17 +218,17 @@ impl qobject::ImageModel { self.as_mut().add_image(img); } println!("--------------------------------------"); - println!("{:?}", self.as_mut().images()); + println!("{:?}", self.as_mut().images); println!("--------------------------------------"); } pub fn remove_item(mut self: Pin<&mut Self>, index: i32) -> bool { - if index < 0 || (index as usize) >= self.images().len() { + if index < 0 || (index as usize) >= self.images.len() { return false; } let db = &mut self.as_mut().get_db(); - let image_id = self.images().get(index as usize).unwrap().id; + let image_id = self.images.get(index as usize).unwrap().id; let result = delete(images.filter(id.eq(image_id))).execute(db); @@ -236,11 +241,14 @@ impl qobject::ImageModel { index, index, ); - self.as_mut().images_mut().remove(index as usize); + self.as_mut() + .rust_mut() + .images + .remove(index as usize); self.as_mut().end_remove_rows(); } println!("removed-item-at-index: {:?}", image_id); - println!("new-Vec: {:?}", self.as_mut().images()); + println!("new-Vec: {:?}", self.as_mut().images); true } Err(_e) => { @@ -273,7 +281,7 @@ impl qobject::ImageModel { if self.as_mut().add_item(image_id, image_title, image_path) { println!("filename: {:?}", name); - self.as_mut().set_highest_id(image_id); + self.as_mut().rust_mut().highest_id = image_id; } else { println!("Error in inserting item"); } @@ -306,7 +314,7 @@ impl qobject::ImageModel { match result { Ok(_i) => { self.as_mut().add_image(image); - println!("{:?}", self.as_mut().images()); + println!("{:?}", self.as_mut().images); true } Err(_e) => { @@ -317,15 +325,17 @@ impl qobject::ImageModel { } fn add_image(mut self: Pin<&mut Self>, image: self::Image) { - let index = self.as_ref().images().len() as i32; + let index = self.as_ref().images.len() as i32; println!("{:?}", image); + let count = self.as_ref().count; + self.as_mut().set_count(count + 1); unsafe { self.as_mut().begin_insert_rows( &QModelIndex::default(), index, index, ); - self.as_mut().images_mut().push(image); + self.as_mut().rust_mut().images.push(image); self.as_mut().end_insert_rows(); } } @@ -337,7 +347,7 @@ impl qobject::ImageModel { ) -> bool { let mut vector_roles = QVector_i32::default(); vector_roles - .append(self.as_ref().get_role_id(Role::TitleRole)); + .append(self.as_ref().get_role_id(ImageRoles::Title)); let model_index = &self.as_ref().index(index, 0, &QModelIndex::default()); @@ -349,14 +359,15 @@ impl qobject::ImageModel { Ok(_i) => { for image in self .as_mut() - .images_mut() + .rust_mut() + .images .iter_mut() .filter(|x| x.id == index) { image.title = updated_title.clone(); println!("rust-title: {:?}", image.title); } - self.as_mut().emit_data_changed( + self.as_mut().data_changed( model_index, model_index, &vector_roles, @@ -374,7 +385,7 @@ impl qobject::ImageModel { ) -> bool { let mut vector_roles = QVector_i32::default(); vector_roles - .append(self.as_ref().get_role_id(Role::PathRole)); + .append(self.as_ref().get_role_id(ImageRoles::Path)); let model_index = &self.as_ref().index(index, 0, &QModelIndex::default()); @@ -386,14 +397,15 @@ impl qobject::ImageModel { Ok(_i) => { for image in self .as_mut() - .images_mut() + .rust_mut() + .images .iter_mut() .filter(|x| x.id == index) { image.path = updated_file_path.clone(); println!("rust-title: {:?}", image.path); } - self.as_mut().emit_data_changed( + self.as_mut().data_changed( model_index, model_index, &vector_roles, @@ -427,25 +439,25 @@ impl qobject::ImageModel { qvariantmap } - fn get_role_id(&self, role: Role) -> i32 { + fn get_role_id(&self, role: ImageRoles) -> i32 { match role { - qobject::Role::Id => 0, - qobject::Role::Title => 1, - qobject::Role::Path => 2, + ImageRoles::Id => 0, + ImageRoles::Title => 1, + ImageRoles::Path => 2, _ => 0, } } } // QAbstractListModel implementation -impl qobject::ImageModel { +impl image_model::ImageModel { fn data(&self, index: &QModelIndex, role: i32) -> QVariant { - let role = qobject::Roles { repr: role }; - if let Some(image) = self.images().get(index.row() as usize) { + let role = ImageRoles { repr: role }; + if let Some(image) = self.images.get(index.row() as usize) { return match role { - qobject::Roles::Id => QVariant::from(&image.id), - qobject::Roles::Title => QVariant::from(&image.title), - qobject::Roles::Path => QVariant::from(&image.path), + ImageRoles::Id => QVariant::from(&image.id), + ImageRoles::Title => QVariant::from(&image.title), + ImageRoles::Path => QVariant::from(&image.path), _ => QVariant::default(), }; } @@ -455,22 +467,22 @@ impl qobject::ImageModel { // Example of overriding a C++ virtual method and calling the base class implementation. - pub fn can_fetch_more(&self, parent: &QModelIndex) -> bool { - self.base_can_fetch_more(parent) - } + // pub fn can_fetch_more(&self, parent: &QModelIndex) -> bool { + // self.base_can_fetch_more(parent) + // } pub fn role_names(&self) -> QHash_i32_QByteArray { let mut roles = QHash_i32_QByteArray::default(); roles.insert( - qobject::Roles::Id.repr, + ImageRoles::Id.repr, cxx_qt_lib::QByteArray::from("id"), ); roles.insert( - qobject::Roles::Title.repr, + ImageRoles::Title.repr, cxx_qt_lib::QByteArray::from("title"), ); roles.insert( - qobject::Roles::Path.repr, + ImageRoles::Path.repr, cxx_qt_lib::QByteArray::from("filePath"), ); roles @@ -482,10 +494,4 @@ impl qobject::ImageModel { // println!("row count is {cnt}"); cnt } - - pub fn count(mut self: Pin<&mut Self>) -> i32 { - let cnt = self.rust().images.len() as i32; - self.as_mut().set_count_rows(cnt); - cnt - } } diff --git a/src/rust/lib.rs b/src/rust/lib.rs index dfbe86d..d04bc21 100644 --- a/src/rust/lib.rs +++ b/src/rust/lib.rs @@ -1,16 +1,16 @@ pub mod ffmpeg; -mod file_helper; +pub mod file_helper; pub mod image_model; pub mod models; pub mod obs; pub mod presentation_model; pub mod reveal_js; pub mod schema; -mod service_item_model; -mod service_thing; +pub mod service_item_model; +pub mod service_thing; pub mod settings; pub mod slide_model; -mod slide_object; +pub mod slide_object; pub mod songs; pub mod utils; pub mod video_model; diff --git a/src/rust/obs.rs b/src/rust/obs.rs index 4a954f9..6e00d6f 100644 --- a/src/rust/obs.rs +++ b/src/rust/obs.rs @@ -1,11 +1,14 @@ use core::fmt; -use std::error::Error; +use std::{error::Error, pin::Pin}; use std::thread::sleep; use std::time::Duration; - +use cxx_qt::CxxQtType; +use cxx_qt_lib::{QStringList, QString}; use obws::responses::scenes::Scenes; use obws::Client; -use tracing::debug; +use tracing::{debug, error}; + +use crate::obs::obs_model::QList_QString; pub struct Obs { scenes: Scenes, @@ -107,8 +110,6 @@ fn make_client() -> Client { #[cxx_qt::bridge] mod obs_model { - use tracing::{debug, error}; - unsafe extern "C++" { include!("cxx-qt-lib/qstring.h"); type QString = cxx_qt_lib::QString; @@ -118,75 +119,84 @@ mod obs_model { type QList_QString = cxx_qt_lib::QList; } - #[cxx_qt::qobject] - #[derive(Debug, Default)] - pub struct ObsModel { - #[qproperty] - scenes: QStringList, - #[qproperty] - port: QString, - #[qproperty] - connected: bool, - obs: Option, + unsafe extern "RustQt" { + #[qobject] + #[qml_element] + #[qproperty(QStringList, scenes)] + #[qproperty(QString, port)] + #[qproperty(bool, connected)] + type ObsModel = super::ObsModelRust; + + #[qinvokable] + fn update_scenes(self: Pin<&mut ObsModel>) -> QStringList; + #[qinvokable] + fn get_obs(self: Pin<&mut ObsModel>) -> bool; + #[qinvokable] + fn set_scene(self: Pin<&mut ObsModel>, scene: QString); + } +} + +#[derive(Debug, Default)] +pub struct ObsModelRust { + scenes: QStringList, + port: QString, + connected: bool, + obs: Option, +} + +impl obs_model::ObsModel { + pub fn update_scenes( + mut self: Pin<&mut Self>, + ) -> QStringList { + debug!("updating scenes"); + let mut scenes_list = QList_QString::default(); + if let Some(obs) = &self.as_mut().rust_mut().obs { + debug!("found obs"); + for scene in obs.scenes.scenes.iter().rev() { + debug!(?scene); + scenes_list.append(QString::from(&scene.name)); + } + } + for s in scenes_list.iter() { + debug!(?s); + } + let list = QStringList::from(&scenes_list); + debug!(?list); + self.as_mut().set_scenes(list.clone()); + list } - impl qobject::ObsModel { - #[qinvokable] - pub fn update_scenes( - mut self: Pin<&mut Self>, - ) -> QStringList { - debug!("updating scenes"); - let mut scenes_list = QList_QString::default(); - if let Some(obs) = self.obs() { - debug!("found obs"); - for scene in obs.scenes.scenes.iter().rev() { - debug!(?scene); - scenes_list.append(QString::from(&scene.name)); + pub fn get_obs(mut self: Pin<&mut Self>) -> bool { + debug!("getting obs"); + + tokio::runtime::Runtime::new().unwrap().block_on(async { + match Obs::new().await { + Ok(o) => { + self.as_mut().set_connected(true); + self.as_mut().rust_mut().obs = Some(o); + self.as_mut().update_scenes(); + } + Err(e) => { + error!(e); + self.as_mut().set_connected(false); } } - for s in scenes_list.iter() { - debug!(?s); - } - let list = QStringList::from(&scenes_list); - debug!(?list); - self.as_mut().set_scenes(list.clone()); - list + }); + + if let Some(_obs) = &self.as_mut().rust_mut().obs { + true + } else { + false } + } - #[qinvokable] - pub fn get_obs(mut self: Pin<&mut Self>) -> bool { - debug!("getting obs"); - - tokio::runtime::Runtime::new().unwrap().block_on(async { - match super::Obs::new().await { - Ok(o) => { - self.as_mut().set_connected(true); - self.as_mut().set_obs(Some(o)); - self.as_mut().update_scenes(); - } - Err(e) => { - error!(e); - self.as_mut().set_connected(false); - } - } - }); - - if let Some(_obs) = self.obs() { - true - } else { - false - } - } - - #[qinvokable] - pub fn set_scene(mut self: Pin<&mut Self>, scene: QString) { - let scene = scene.to_string(); - if let Some(obs) = self.obs_mut() { - let obs = obs.clone(); - match obs.set_scene(scene) { - Ok(()) => debug!("Successfully set scene"), - Err(e) => error!(e), - } + pub fn set_scene(mut self: Pin<&mut Self>, scene: QString) { + let scene = scene.to_string(); + if let Some(obs) = &self.as_mut().rust_mut().obs { + let obs = obs.clone(); + match obs.set_scene(scene) { + Ok(()) => debug!("Successfully set scene"), + Err(e) => error!(e), } } } diff --git a/src/rust/presentation_model.rs b/src/rust/presentation_model.rs index 1e9bb0c..e56465a 100644 --- a/src/rust/presentation_model.rs +++ b/src/rust/presentation_model.rs @@ -25,7 +25,7 @@ mod presentation_model { } #[qenum(PresentationModel)] - enum Role { + enum PresRoles { Id, Title, Path, @@ -37,7 +37,7 @@ mod presentation_model { #[qobject] #[base = "QAbstractListModel"] #[qml_element] - #[qproperty(i32, count_rows)] + #[qproperty(i32, count)] type PresentationModel = super::PresentationModelRust; #[inherit] @@ -64,24 +64,18 @@ mod presentation_model { url: QUrl, new_page_count: i32, ); - #[qinvokable] - fn update_path( - self: Pin<&mut PresentationModel>, - index: i32, - updated_path: QString, - ) -> bool; + // #[qinvokable] + // fn update_path( + // self: Pin<&mut PresentationModel>, + // index: i32, + // updated_path: QString, + // ) -> bool; #[qinvokable] fn get_item( self: Pin<&mut PresentationModel>, index: i32, ) -> QMap_QString_QVariant; #[qinvokable] - fn update_loop( - self: Pin<&mut PresentationModel>, - index: i32, - loop_value: bool, - ) -> bool; - #[qinvokable] fn update_title( self: Pin<&mut PresentationModel>, index: i32, @@ -93,12 +87,6 @@ mod presentation_model { index: i32, updated_page_count: i32, ) -> bool; - #[qinvokable] - fn update_end_time( - self: Pin<&mut PresentationModel>, - index: i32, - updated_end_stime: QString, - ) -> bool; } impl cxx_qt::Threading for PresentationModel {} @@ -181,21 +169,25 @@ mod presentation_model { self: &PresentationModel, _parent: &QModelIndex, ) -> i32; - - #[qinvokable] - fn count(self: &PresentationModel) -> i32; } } -use crate::presentation_model::presentation_model::Presentation; +use crate::presentation_model::presentation_model::QMap_QString_QVariant; use crate::reveal_js; use crate::schema::presentations::dsl::*; +use cxx_qt::CxxQtType; +use cxx_qt_lib::{QModelIndex, QString, QUrl, QVariant}; use diesel::sqlite::SqliteConnection; use diesel::{delete, insert_into, prelude::*, update}; // use sqlx::Connection; use std::path::PathBuf; +use std::pin::Pin; use tracing::debug; +use self::presentation_model::{ + PresRoles, QHash_i32_QByteArray, QVector_i32, +}; + #[derive(Default, Clone, Debug)] pub struct Presentation { id: i32, @@ -207,15 +199,16 @@ pub struct Presentation { #[derive(Default, Debug)] pub struct PresentationModelRust { + count: i32, highest_id: i32, - presentations: Vec, + presentations: Vec, } -impl qobject::PresentationModel { +impl presentation_model::PresentationModel { pub fn clear(mut self: Pin<&mut Self>) { unsafe { self.as_mut().begin_reset_model(); - self.as_mut().presentations_mut().clear(); + self.as_mut().rust_mut().presentations.clear(); self.as_mut().end_reset_model(); } } @@ -227,7 +220,7 @@ impl qobject::PresentationModel { let results = presentations .load::(db) .expect("Error loading presentations"); - self.as_mut().set_highest_id(0); + self.as_mut().rust_mut().highest_id = 0; println!("SHOWING PRESENTATIONS"); println!("--------------"); @@ -237,8 +230,8 @@ impl qobject::PresentationModel { println!("{}", presentation.path); println!("{}", presentation.html); println!("--------------"); - if self.as_mut().highest_id() < &presentation.id { - self.as_mut().set_highest_id(presentation.id); + if &self.as_mut().highest_id < &presentation.id { + self.as_mut().rust_mut().highest_id = presentation.id; } let pres = self::Presentation { @@ -249,22 +242,23 @@ impl qobject::PresentationModel { page_count: presentation.page_count.unwrap(), }; + let count = self.as_ref().count; + self.as_mut().set_count(count + 1); self.as_mut().add_presentation(pres); } println!("--------------------------------------"); - println!("{:?}", self.as_mut().presentations()); + println!("{:?}", self.as_mut().presentations); println!("--------------------------------------"); } pub fn remove_item(mut self: Pin<&mut Self>, index: i32) -> bool { - if index < 0 || (index as usize) >= self.presentations().len() - { + if index < 0 || (index as usize) >= self.presentations.len() { return false; } let db = &mut self.as_mut().get_db(); let presentation_id = - self.presentations().get(index as usize).unwrap().id; + self.presentations.get(index as usize).unwrap().id; let result = delete(presentations.filter(id.eq(presentation_id))) @@ -279,7 +273,8 @@ impl qobject::PresentationModel { index, ); self.as_mut() - .presentations_mut() + .rust_mut() + .presentations .remove(index as usize); self.as_mut().end_remove_rows(); } @@ -289,7 +284,7 @@ impl qobject::PresentationModel { ); println!( "new-Vec: {:?}", - self.as_mut().presentations() + self.as_mut().presentations ); true } @@ -321,7 +316,7 @@ impl qobject::PresentationModel { println!("LETS INSERT THIS SUCKER!"); let file_path = PathBuf::from(url.path().to_string()); let name = file_path.file_stem().unwrap().to_str().unwrap(); - let presentation_id = self.rust().highest_id + 1; + let presentation_id = self.highest_id + 1; let presentation_title = QString::from(name); let presentation_path = url; let presentation_html = @@ -336,7 +331,7 @@ impl qobject::PresentationModel { new_page_count, ) { println!("filename: {:?}", name); - self.as_mut().set_highest_id(presentation_id); + self.as_mut().rust_mut().highest_id = presentation_id; } else { println!("Error in inserting item"); } @@ -387,7 +382,7 @@ impl qobject::PresentationModel { match result { Ok(_i) => { self.as_mut().add_presentation(presentation); - println!("{:?}", self.as_mut().presentations()); + println!("{:?}", self.as_mut().presentations); true } Err(_e) => { @@ -401,7 +396,7 @@ impl qobject::PresentationModel { mut self: Pin<&mut Self>, presentation: self::Presentation, ) { - let index = self.as_ref().presentations().len() as i32; + let index = self.as_ref().presentations.len() as i32; println!("{:?}", presentation); unsafe { self.as_mut().begin_insert_rows( @@ -409,7 +404,7 @@ impl qobject::PresentationModel { index, index, ); - self.as_mut().presentations_mut().push(presentation); + self.as_mut().rust_mut().presentations.push(presentation); self.as_mut().end_insert_rows(); } } @@ -427,7 +422,7 @@ impl qobject::PresentationModel { let role_names = self.as_ref().role_names(); let role_names_iter = role_names.iter(); if let Some(presentation) = - self.rust().presentations.get(index as usize) + self.presentations.get(index as usize) { for i in role_names_iter { qvariantmap.insert( @@ -445,7 +440,7 @@ impl qobject::PresentationModel { updated_title: QString, ) -> bool { let mut vector_roles = QVector_i32::default(); - vector_roles.append(self.as_ref().get_role(Role::TitleRole)); + vector_roles.append(self.as_ref().get_role(PresRoles::Title)); let model_index = &self.as_ref().index(index, 0, &QModelIndex::default()); @@ -457,7 +452,8 @@ impl qobject::PresentationModel { Ok(_i) => { for presentation in self .as_mut() - .presentations_mut() + .rust_mut() + .presentations .iter_mut() .filter(|x| x.id == index) { @@ -465,7 +461,7 @@ impl qobject::PresentationModel { println!("rust-title: {:?}", presentation.title); } // TODO this seems to not be updating in the actual list - self.as_mut().emit_data_changed( + self.as_mut().data_changed( model_index, model_index, &vector_roles, @@ -485,7 +481,7 @@ impl qobject::PresentationModel { ) -> bool { let mut vector_roles = QVector_i32::default(); vector_roles - .append(self.as_ref().get_role(Role::PageCountRole)); + .append(self.as_ref().get_role(PresRoles::PageCount)); let model_index = &self.as_ref().index(index, 0, &QModelIndex::default()); @@ -497,7 +493,8 @@ impl qobject::PresentationModel { Ok(_i) => { for presentation in self .as_mut() - .presentations_mut() + .rust_mut() + .presentations .iter_mut() .filter(|x| x.id == index) { @@ -508,7 +505,7 @@ impl qobject::PresentationModel { ); } // TODO this seems to not be updating in the actual list - self.as_mut().emit_data_changed( + self.as_mut().data_changed( model_index, model_index, &vector_roles, @@ -521,37 +518,35 @@ impl qobject::PresentationModel { } } - fn get_role(&self, role: Role) -> i32 { + fn get_role(&self, role: PresRoles) -> i32 { match role { - Role::IdRole => 0, - Role::TitleRole => 1, - Role::PathRole => 2, - Role::HtmlRole => 3, - Role::PageCountRole => 4, + PresRoles::Id => 0, + PresRoles::Title => 1, + PresRoles::Path => 2, + PresRoles::Html => 3, + PresRoles::PageCount => 4, _ => 0, } } } // QAbstractListModel implementation -impl qobject::PresentationModel { +impl presentation_model::PresentationModel { fn data(&self, index: &QModelIndex, role: i32) -> QVariant { - let role = qobject::Roles { repr: role }; + let role = PresRoles { repr: role }; if let Some(presentation) = - self.presentations().get(index.row() as usize) + self.presentations.get(index.row() as usize) { return match role { - qobject::Role::Id => QVariant::from(&presentation.id), - qobject::Role::Title => QVariant::from( - &QString::from(&presentation.title), - ), - qobject::Role::Path => { + PresRoles::Id => QVariant::from(&presentation.id), + PresRoles::Title => QVariant::from(&QString::from( + &presentation.title, + )), + PresRoles::Path => { QVariant::from(&QString::from(&presentation.path)) } - qobject::Role::Html => { - QVariant::from(&presentation.html) - } - qobject::Role::PageCount => { + PresRoles::Html => QVariant::from(&presentation.html), + PresRoles::PageCount => { QVariant::from(&presentation.page_count) } _ => QVariant::default(), @@ -563,42 +558,38 @@ impl qobject::PresentationModel { // Example of overriding a C++ virtual method and calling the base class implementation. - pub fn can_fetch_more(&self, parent: &QModelIndex) -> bool { - self.base_can_fetch_more(parent) - } + // pub fn can_fetch_more(&self, parent: &QModelIndex) -> bool { + // self.base_can_fetch_more(parent) + // } pub fn role_names(&self) -> QHash_i32_QByteArray { let mut roles = QHash_i32_QByteArray::default(); roles.insert( - qobject::Roles::Id.repr, + PresRoles::Id.repr, cxx_qt_lib::QByteArray::from("id"), ); roles.insert( - qobject::Roles::Title.repr, + PresRoles::Title.repr, cxx_qt_lib::QByteArray::from("title"), ); roles.insert( - qobject::Roles::Path.repr, + PresRoles::Path.repr, cxx_qt_lib::QByteArray::from("filePath"), ); roles.insert( - qobject::Roles::Html.repr, + PresRoles::Html.repr, cxx_qt_lib::QByteArray::from("html"), ); roles.insert( - qobject::Roles::PageCount.repr, + PresRoles::PageCount.repr, cxx_qt_lib::QByteArray::from("pageCount"), ); roles } pub fn row_count(&self, _parent: &QModelIndex) -> i32 { - let cnt = self.rust().presentations.len() as i32; + let cnt = self.presentations.len() as i32; // println!("row count is {cnt}"); cnt } - - pub fn count(&self) -> i32 { - self.rust().presentations.len() as i32 - } } diff --git a/src/rust/service_item_model.rs b/src/rust/service_item_model.rs index bc8b933..a76d09f 100644 --- a/src/rust/service_item_model.rs +++ b/src/rust/service_item_model.rs @@ -25,7 +25,7 @@ mod service_item_model { } #[qenum(ServiceItemModel)] - enum Role { + enum ServiceRoles { Name, Type, Audio, @@ -46,6 +46,7 @@ mod service_item_model { #[qobject] #[base = "QAbstractListModel"] #[qml_element] + #[qproperty(i32, count)] type ServiceItemModel = super::ServiceItemModelRust; #[inherit] @@ -134,7 +135,7 @@ mod service_item_model { fn move_down(self: Pin<&mut ServiceItemModel>, index: i32) -> bool; #[qinvokable] - fn select(self: Pin<&mut ServiceItemModel>, index: i32) -> bool; + fn select(self: Pin<&mut ServiceItemModel>, index: i32); #[qinvokable] fn select_items( @@ -240,28 +241,32 @@ mod service_item_model { fn row_count(self: &ServiceItemModel, _parent: &QModelIndex) -> i32; - #[qinvokable] - fn count(self: &ServiceItemModel) -> i32; } } +use cxx_qt::CxxQtType; +use cxx_qt_lib::{QModelIndex, QStringList, QString, QByteArray, QUrl, QVariant}; use dirs; use serde_json::{json, Deserializer, Map, Serializer, Value}; use std::ffi::{OsStr, OsString}; use std::io::{self, Read, Write}; use std::iter; use std::path::{Path, PathBuf}; +use std::pin::Pin; use std::str; use std::{fs, println}; use tar::{Archive, Builder}; use tracing::{debug, debug_span, error, info, instrument}; use zstd::{Decoder, Encoder}; use crate::obs::Obs; +use crate::service_item_model::service_item_model::QList_QString; use serde::{Deserialize, Serialize}; +use self::service_item_model::{QMap_QString_QVariant, QVector_i32, QHash_i32_QByteArray, ServiceRoles}; + #[derive(Clone, Debug)] -pub struct ServiceItm { +pub struct ServiceItem { name: QString, ty: QString, audio: QString, @@ -279,7 +284,7 @@ pub struct ServiceItm { obs_scene: QString, } -impl Default for ServiceItm { +impl Default for ServiceItem { fn default() -> Self { Self { name: QString::default(), @@ -304,8 +309,9 @@ impl Default for ServiceItm { #[derive(Debug)] pub struct ServiceItemModelRust { id: i32, - service_items: Vec, + service_items: Vec, obs: Option, + count: i32, } impl Default for ServiceItemModelRust { @@ -325,11 +331,12 @@ impl Default for ServiceItemModelRust { id: 0, service_items: Vec::new(), obs, + count: 0, } } } -impl qobject::ServiceItemModel { +impl service_item_model::ServiceItemModel { pub fn setup(mut self: Pin<&mut Self>) { todo!() } @@ -338,15 +345,15 @@ impl qobject::ServiceItemModel { println!("CLEARING ALL ITEMS"); unsafe { self.as_mut().begin_reset_model(); - self.as_mut().service_items_mut().clear(); + self.as_mut().rust_mut().service_items.clear(); self.as_mut().end_reset_model(); } - self.emit(Signals::Cleared {}); + self.as_mut().cleared(); } pub fn remove_item(mut self: Pin<&mut Self>, index: i32) { if index < 0 - || (index as usize) >= self.service_items().len() + || (index as usize) >= self.service_items.len() { return; } @@ -357,13 +364,13 @@ impl qobject::ServiceItemModel { index, index, ); - self.as_mut() - .service_items_mut() + self.as_mut().rust_mut() + .service_items .remove(index as usize); self.as_mut().end_remove_rows(); } let item = self.as_mut().get_item(index); - self.as_mut().emit_item_removed(&index, &item); + self.as_mut().item_removed(&index, &item); } pub fn add_item( @@ -381,7 +388,7 @@ impl qobject::ServiceItemModel { video_start_time: f32, video_end_time: f32, ) { - let service_item = ServiceItm { + let service_item = ServiceItem { name, ty, text, @@ -402,22 +409,24 @@ impl qobject::ServiceItemModel { fn add_service_item( mut self: Pin<&mut Self>, - service_item: &ServiceItm, + service_item: &ServiceItem, ) { - let index = self.as_ref().service_items().len() as i32; + let index = self.as_ref().service_items.len() as i32; println!("{:?}", service_item); let service_item = service_item.clone(); + let count = self.as_ref().count; + self.as_mut().set_count(count + 1); unsafe { self.as_mut().begin_insert_rows( &QModelIndex::default(), index, index, ); - self.as_mut().service_items_mut().push(service_item); + self.as_mut().rust_mut().service_items.push(service_item); self.as_mut().end_insert_rows(); } let item = self.as_mut().get_item(index); - self.as_mut().emit_item_added(&index, &item); + self.as_mut().item_added(&index, &item); } pub fn insert_item( @@ -436,7 +445,7 @@ impl qobject::ServiceItemModel { video_start_time: f32, video_end_time: f32, ) { - let service_item = ServiceItm { + let service_item = ServiceItem { name, ty, text, @@ -457,7 +466,7 @@ impl qobject::ServiceItemModel { fn insert_service_item( mut self: Pin<&mut Self>, - service_item: &ServiceItm, + service_item: &ServiceItem, id: i32, ) { let service_item = service_item.clone(); @@ -467,13 +476,13 @@ impl qobject::ServiceItemModel { id, id, ); - self.as_mut() - .service_items_mut() + self.as_mut().rust_mut() + .service_items .insert(id as usize, service_item); self.as_mut().end_insert_rows(); } let item = self.as_mut().get_item(id); - self.as_mut().emit_item_inserted(&id, &item); + self.as_mut().item_inserted(&id, &item); } pub fn get_item( @@ -489,7 +498,7 @@ impl qobject::ServiceItemModel { let rn = self.as_ref().role_names(); let rn_iter = rn.iter(); if let Some(service_item) = - self.rust().service_items.get(index as usize) + self.service_items.get(index as usize) { for i in rn_iter { map.insert( @@ -541,7 +550,7 @@ impl qobject::ServiceItemModel { if source_id < dest_id { let move_amount = dest_id - source_id - cnt + 1; - self.as_mut().service_items_mut() + self.as_mut().rust_mut().service_items [source_id..=dest_id] .rotate_right(move_amount); println!("rust-move_amount: {:?}", move_amount); @@ -549,18 +558,14 @@ impl qobject::ServiceItemModel { let move_amount = end_service_item - dest_id - cnt + 1; println!("rust-move_amount: {:?}", move_amount); - self.as_mut().service_items_mut() + self.as_mut().rust_mut().service_items [dest_id..=end_service_item] .rotate_left(move_amount); } self.as_mut().end_move_rows(); let item = self.as_mut().get_item(dest_index); - self.as_mut().emit_item_moved( - &source_index, - &dest_index, - &item, - ); + self.as_mut().item_moved(&source_index, &dest_index, &item); true } } @@ -573,38 +578,31 @@ impl qobject::ServiceItemModel { self.move_rows(index, index + 1, 1) } - pub fn select(mut self: Pin<&mut Self>, index: i32) -> bool { + pub fn select(mut self: Pin<&mut Self>, index: i32) { let rc = self.as_ref().count() - 1; let tl = &self.as_ref().index(0, 0, &QModelIndex::default()); let br = &self.as_ref().index(rc, 0, &QModelIndex::default()); let mut vector_roles = QVector_i32::default(); - vector_roles.append(self.get_role(Role::SelectedRole)); + vector_roles.append(self.get_role(ServiceRoles::Selected)); for service_item in - self.as_mut().service_items_mut().iter_mut() + self.as_mut().rust_mut().service_items.iter_mut() { debug!(deselecting = ?service_item); service_item.selected = false; } if let Some(service_item) = self - .as_mut() - .service_items_mut() + .as_mut().rust_mut() + .service_items .get_mut(index as usize) { debug!(selecting_item = index, item = ?service_item); service_item.selected = true; - self.as_mut().emit_data_changed( - tl, - br, - &vector_roles, - ); + self.as_mut().data_changed(tl, br, &vector_roles); // We use this signal generated by our signals enum to tell QML that // the selected service_item has changed which is used to reposition views. // self.as_mut().emit_selected_changed(); - true - } else { - false } } @@ -615,11 +613,11 @@ impl qobject::ServiceItemModel { // setup the roles we are using so that we can tell QML // which properties to get again. let mut vector_roles = QVector_i32::default(); - vector_roles.append(self.get_role(Role::SelectedRole)); + vector_roles.append(self.get_role(ServiceRoles::Selected)); if let Some(current_index) = self .as_ref() - .service_items() + .service_items .iter() .position(|i| i.selected == true) { @@ -644,8 +642,8 @@ impl qobject::ServiceItemModel { &QModelIndex::default(), ); for (index, item) in self - .as_mut() - .service_items_mut() + .as_mut().rust_mut() + .service_items .iter_mut() .enumerate() .filter(|i| { @@ -656,11 +654,7 @@ impl qobject::ServiceItemModel { item.selected = true; debug!(selected_item = ?item, index = index); } - self.as_mut().emit_data_changed( - top_left, - bottom_right, - &vector_roles, - ); + self.as_mut().data_changed(top_left, bottom_right, &vector_roles); // self.as_mut().emit_selected_changed(); } else { let top_left = &self.as_ref().index( @@ -674,8 +668,8 @@ impl qobject::ServiceItemModel { &QModelIndex::default(), ); for (index, item) in self - .as_mut() - .service_items_mut() + .as_mut().rust_mut() + .service_items .iter_mut() .enumerate() .filter(|i| { @@ -686,12 +680,7 @@ impl qobject::ServiceItemModel { item.selected = true; debug!(selected_item = ?item, index = index); } - self.as_mut().emit_data_changed( - top_left, - bottom_right, - &vector_roles, - ); - // self.as_mut().emit_selected_changed(); + self.as_mut().data_changed(top_left, bottom_right, &vector_roles); } true @@ -711,8 +700,8 @@ impl qobject::ServiceItemModel { &QModelIndex::default(), ); for (index, item) in self - .as_mut() - .service_items_mut() + .as_mut().rust_mut() + .service_items .iter_mut() .enumerate() .filter(|i| i.0 <= final_index as usize) @@ -720,12 +709,7 @@ impl qobject::ServiceItemModel { item.selected = true; debug!(selected_item = ?item, index = index); } - self.as_mut().emit_data_changed( - top_left, - bottom_right, - &vector_roles, - ); - // self.as_mut().emit_selected_changed(); + self.as_mut().data_changed(top_left, bottom_right, &vector_roles); debug!( first_item = 0, final_item = final_index, @@ -745,18 +729,18 @@ impl qobject::ServiceItemModel { let br = &self.as_ref().index(rc, 0, &QModelIndex::default()); let mut vector_roles = QVector_i32::default(); - vector_roles.append(self.get_role(Role::ActiveRole)); + vector_roles.append(self.get_role(ServiceRoles::Active)); for service_item in - self.as_mut().service_items_mut().iter_mut() + self.as_mut().rust_mut().service_items.iter_mut() { // println!("service_item is deactivating {:?}", i); service_item.active = false; } - let obs = self.as_mut().obs_mut().clone(); + let obs = self.as_mut().obs.clone(); if let Some(service_item) = self - .as_mut() - .service_items_mut() + .as_mut().rust_mut() + .service_items .get_mut(index as usize) { debug!(activating_item = index, @@ -772,14 +756,10 @@ impl qobject::ServiceItemModel { // Err(e) => error!(e), // } // } - self.as_mut().emit_data_changed( - tl, - br, - &vector_roles, - ); + self.as_mut().data_changed(tl, br, &vector_roles); // We use this signal generated by our signals enum to tell QML that // the active service_item has changed which is used to reposition views. - self.as_mut().emit_active_changed(&index); + self.as_mut().active_changed(&index); true } else { false @@ -796,10 +776,10 @@ impl qobject::ServiceItemModel { let br = &self.as_ref().index(rc, 0, &QModelIndex::default()); let mut vector_roles = QVector_i32::default(); - vector_roles.append(self.get_role(Role::ActiveRole)); + vector_roles.append(self.get_role(ServiceRoles::Active)); if let Some(service_item) = self - .as_mut() - .service_items_mut() + .as_mut().rust_mut() + .service_items .get_mut(index as usize) { println!("service_item is activating {:?}", index); @@ -816,11 +796,7 @@ impl qobject::ServiceItemModel { service_item.background_type ); service_item.active = false; - self.as_mut().emit_data_changed( - tl, - br, - &vector_roles, - ); + self.as_mut().data_changed(tl, br, &vector_roles); // We use this signal generated by our signals enum to tell QML that // the active service_item has changed which is used to reposition views. // self.as_mut().emit_active_changed(index); @@ -840,7 +816,7 @@ impl qobject::ServiceItemModel { println!("archive: {:?}", lf); let encoder = Encoder::new(lf, 3).unwrap(); let mut tar = Builder::new(encoder); - let items = self.service_items(); + let items = &self.service_items; let mut temp_dir = dirs::data_dir().unwrap(); temp_dir.push("lumina"); let mut s: String = @@ -1244,7 +1220,7 @@ impl qobject::ServiceItemModel { } let text = QStringList::from(&text_list); - let service_item = ServiceItm { + let service_item = ServiceItem { name, ty, text, @@ -1276,53 +1252,53 @@ impl qobject::ServiceItemModel { // Don't actually need } - fn get_role(&self, role: Role) -> i32 { + fn get_role(&self, role: ServiceRoles) -> i32 { match role { - Role::NameRole => 0, - Role::TyRole => 1, - Role::AudioRole => 2, - Role::BackgroundRole => 3, - Role::BackgroundTypeRole => 4, - Role::TextRole => 5, - Role::FontRole => 6, - Role::FontSizeRole => 7, - Role::SlideCountRole => 8, - Role::ActiveRole => 9, - Role::SelectedRole => 10, - Role::LoopingRole => 11, - Role::VideoStartTimeRole => 12, - Role::VideoEndTimeRole => 13, + ServiceRoles::Name => 0, + ServiceRoles::Type => 1, + ServiceRoles::Audio => 2, + ServiceRoles::Background => 3, + ServiceRoles::BackgroundType => 4, + ServiceRoles::Text => 5, + ServiceRoles::Font => 6, + ServiceRoles::FontSize => 7, + ServiceRoles::SlideCount => 8, + ServiceRoles::Active => 9, + ServiceRoles::Selected => 10, + ServiceRoles::Looping => 11, + ServiceRoles::VideoStartTime => 12, + ServiceRoles::VideoEndTime => 13, _ => 0, } } } // QAbstractListModel implementation -impl qobject::ServiceItemMod { +impl service_item_model::ServiceItemModel { fn data(&self, index: &QModelIndex, role: i32) -> QVariant { - let role = qobject::Roles { repr: role }; + let role = ServiceRoles { repr: role }; if let Some(service_item) = - self.service_items().get(index.row() as usize) + self.service_items.get(index.row() as usize) { return match role { - qobject::Roles::Name => QVariant::from(&service_item.name), - qobject::Roles::Type => QVariant::from(&service_item.ty), - qobject::Roles::Audio => QVariant::from(&service_item.audio), - qobject::Roles::Background => QVariant::from(&service_item.background), - qobject::Roles::BackgroundType => { + ServiceRoles::Name => QVariant::from(&service_item.name), + ServiceRoles::Type => QVariant::from(&service_item.ty), + ServiceRoles::Audio => QVariant::from(&service_item.audio), + ServiceRoles::Background => QVariant::from(&service_item.background), + ServiceRoles::BackgroundType => { QVariant::from(&service_item.background_type) } - qobject::Roles::Text => QVariant::from(&service_item.text), - qobject::Roles::Font => QVariant::from(&service_item.font), - qobject::Roles::FontSize => QVariant::from(&service_item.font_size), - qobject::Roles::SlideCount => QVariant::from(&service_item.slide_count), - qobject::Roles::Active => QVariant::from(&service_item.active), - qobject::Roles::Selected => QVariant::from(&service_item.selected), - qobject::Roles::Looping => QVariant::from(&service_item.looping), - qobject::Roles::VideoStartTime => { + ServiceRoles::Text => QVariant::from(&service_item.text), + ServiceRoles::Font => QVariant::from(&service_item.font), + ServiceRoles::FontSize => QVariant::from(&service_item.font_size), + ServiceRoles::SlideCount => QVariant::from(&service_item.slide_count), + ServiceRoles::Active => QVariant::from(&service_item.active), + ServiceRoles::Selected => QVariant::from(&service_item.selected), + ServiceRoles::Looping => QVariant::from(&service_item.looping), + ServiceRoles::VideoStartTime => { QVariant::from(&service_item.video_start_time) } - qobject::Roles::VideoEndTime => { + ServiceRoles::VideoEndTime => { QVariant::from(&service_item.video_end_time) } _ => QVariant::default(), @@ -1332,53 +1308,49 @@ impl qobject::ServiceItemMod { QVariant::default() } - // Example of overriding a C++ virtual method and calling the base class implementation. - pub fn can_fetch_more(&self, parent: &QModelIndex) -> bool { - self.base_can_fetch_more(parent) - } + // // Example of overriding a C++ virtual method and calling the base class implementation. + // pub fn can_fetch_more(&self, parent: &QModelIndex) -> bool { + // self.base_can_fetch_more(parent) + // } pub fn role_names(&self) -> QHash_i32_QByteArray { let mut roles = QHash_i32_QByteArray::default(); - roles.insert(qobject::Roles::Name.repr, cxx_qt_lib::QByteArray::from("name")); - roles.insert(qobject::Roles::Type.repr, cxx_qt_lib::QByteArray::from("ty")); - roles.insert(qobject::Roles::Audio.repr, cxx_qt_lib::QByteArray::from("audio")); + roles.insert(ServiceRoles::Name.repr, QByteArray::from("name")); + roles.insert(ServiceRoles::Type.repr, QByteArray::from("ty")); + roles.insert(ServiceRoles::Audio.repr, QByteArray::from("audio")); roles.insert( - qobject::Roles::Background.repr, - cxx_qt_lib::QByteArray::from("background"), + ServiceRoles::Background.repr, + QByteArray::from("background"), ); roles.insert( - qobject::Roles::BackgroundType, - cxx_qt_lib::QByteArray::from("backgroundType"), + ServiceRoles::BackgroundType.repr, + QByteArray::from("backgroundType"), ); - roles.insert(qobject::Roles::Text.repr, cxx_qt_lib::QByteArray::from("text")); - roles.insert(qobject::Roles::Font.repr, cxx_qt_lib::QByteArray::from("font")); - roles.insert(qobject::Roles::FontSize.repr, cxx_qt_lib::QByteArray::from("fontSize")); + roles.insert(ServiceRoles::Text.repr, QByteArray::from("text")); + roles.insert(ServiceRoles::Font.repr, QByteArray::from("font")); + roles.insert(ServiceRoles::FontSize.repr, QByteArray::from("fontSize")); roles.insert( - qobject::Roles::SlideCount.repr, - cxx_qt_lib::QByteArray::from("slideCount"), + ServiceRoles::SlideCount.repr, + QByteArray::from("slideCount"), ); - roles.insert(qobject::Roles::Active.repr, cxx_qt_lib::QByteArray::from("active")); + roles.insert(ServiceRoles::Active.repr, QByteArray::from("active")); roles - .insert(qobject::Roles::Selected.repr, cxx_qt_lib::QByteArray::from("selected")); - roles.insert(qobject::Roles::Looping.repr, cxx_qt_lib::QByteArray::from("looping")); + .insert(ServiceRoles::Selected.repr, QByteArray::from("selected")); + roles.insert(ServiceRoles::Looping.repr, QByteArray::from("looping")); roles.insert( - qobject::Roles::VideoStartTime.repr, - cxx_qt_lib::QByteArray::from("videoStartTime"), + ServiceRoles::VideoStartTime.repr, + QByteArray::from("videoStartTime"), ); roles.insert( - qobject::Roles::VideoEndTime.repr, - cxx_qt_lib::QByteArray::from("videoEndTime"), + ServiceRoles::VideoEndTime.repr, + QByteArray::from("videoEndTime"), ); roles } pub fn row_count(&self, _parent: &QModelIndex) -> i32 { - let cnt = self.rust().service_items.len() as i32; + let cnt = self.service_items.len() as i32; // println!("row count is {cnt}"); cnt } - - pub fn count(&self) -> i32 { - self.rust().service_items.len() as i32 - } } diff --git a/src/rust/service_thing.rs b/src/rust/service_thing.rs index a46fbd6..e123dfe 100644 --- a/src/rust/service_thing.rs +++ b/src/rust/service_thing.rs @@ -31,6 +31,7 @@ mod service_thing { } use cxx_qt_lib::QString; +use std::pin::Pin; #[derive(Clone)] pub struct ServiceThingRust { @@ -63,7 +64,7 @@ impl Default for ServiceThingRust { } } -impl qobject::ServiceThing { +impl service_thing::ServiceThing { pub fn activate(self: Pin<&mut Self>) { println!("{}", self.active()); let active: bool = *self.active(); diff --git a/src/rust/settings.rs b/src/rust/settings.rs index 6c36de9..e1257e1 100644 --- a/src/rust/settings.rs +++ b/src/rust/settings.rs @@ -25,8 +25,10 @@ mod settings { } use configparser::ini::Ini; +use cxx_qt::CxxQtType; +use cxx_qt_lib::{QString, QUrl}; use dirs; -use std::path::PathBuf; +use std::{path::PathBuf, pin::Pin}; // In order for settings to save to the ini file, // I'll need to create my own setting functions I think. @@ -52,19 +54,19 @@ impl Default for SettingsRust { } } -impl qobject::Settings { +impl settings::Settings { pub fn setup(mut self: Pin<&mut Self>) { let home = dirs::config_dir(); println!("{:?}", home); if let Some(mut conf) = home { conf.push("lumina"); conf.push("lumina.conf"); - match self.as_mut().config_mut().load(conf) { + match self.as_mut().rust_mut().config.load(conf) { Ok(map) => { // println!("{:?}", self.rust().config); let sf = self .as_ref() - .config() + .config .get("General", "lastSaveFile"); println!("{:?}", sf); if let Some(s) = sf { @@ -87,7 +89,7 @@ impl qobject::Settings { pub fn set_save_file(mut self: Pin<&mut Self>, file: QUrl) { println!("{file}"); - match self.as_mut().config_mut().set( + match self.as_mut().rust_mut().config.set( "General", "lastSaveFile", Some(file.to_string()), @@ -96,7 +98,7 @@ impl qobject::Settings { println!( "set-save-file: {:?}", self.as_mut() - .config_mut() + .config .get("General", "lastSaveFile") ); if let Err(e) = self.as_mut().write() { @@ -112,7 +114,7 @@ impl qobject::Settings { let mut file = dirs::config_dir().unwrap(); file.push("lumina"); file.push("lumina.conf"); - match self.as_mut().config_mut().write(file) { + match self.as_mut().config.write(file) { Ok(_s) => Ok("Saved File"), Err(e) => { println!("error: {:?}", e); diff --git a/src/rust/slide_model.rs b/src/rust/slide_model.rs index 5ee22f5..b9bd2df 100644 --- a/src/rust/slide_model.rs +++ b/src/rust/slide_model.rs @@ -27,7 +27,7 @@ mod slide_model { } #[qenum(SlideModel)] - enum Role { + enum SlideRoles { Ty, Text, Audio, @@ -39,7 +39,7 @@ mod slide_model { FontSize, ServiceItemId, SlideIndex, - ImageCount, + SlideCount, Active, Selected, Looping, @@ -53,6 +53,7 @@ mod slide_model { #[qobject] #[base = "QAbstractListModel"] #[qml_element] + #[qproperty(i32, count)] type SlideModel = super::SlideModelRust; #[inherit] @@ -186,17 +187,25 @@ mod slide_model { fn row_count(self: &SlideModel, _parent: &QModelIndex) -> i32; - #[qinvokable] - fn count(self: &SlideModel) -> i32; } } use crate::ffmpeg; -use cxx_qt_lib::CaseSensitivity; -use std::path::PathBuf; +use crate::slide_model::slide_model::QList_QString; +use cxx_qt::{CxxQtType, Threading}; +use cxx_qt_lib::{ + CaseSensitivity, QByteArray, QModelIndex, QString, QStringList, + QVariant, +}; use std::thread; +use std::{path::PathBuf, pin::Pin}; use tracing::{debug, debug_span, error, info, instrument}; +use self::slide_model::{ + QHash_i32_QByteArray, QMap_QString_QVariant, QVector_i32, + SlideRoles, +}; + #[derive(Clone, Debug)] pub struct Slide { text: QString, @@ -250,20 +259,22 @@ impl Default for Slide { pub struct SlideModelRust { id: i32, slides: Vec, + count: i32, } -impl qobject::SlideModel { +impl slide_model::SlideModel { pub fn add_video_thumbnail( mut self: Pin<&mut Self>, index: i32, ) -> bool { let mut vector_roles = QVector_i32::default(); - vector_roles.append(self.get_role(Role::VideoThumbnailRole)); + vector_roles + .append(self.get_role(SlideRoles::VideoThumbnail)); let model_index = &self.index(index, 0, &QModelIndex::default()); if let Some(slide) = - self.as_mut().slides_mut().get_mut(index as usize) + self.as_mut().rust_mut().slides.get_mut(index as usize) { if !slide.video_background.is_empty() { let path = @@ -274,7 +285,7 @@ impl qobject::SlideModel { .insert(0, &QString::from("file://")) .to_owned(); slide.video_thumbnail = video; - self.as_mut().emit_data_changed( + self.as_mut().data_changed( model_index, model_index, &vector_roles, @@ -288,7 +299,7 @@ impl qobject::SlideModel { println!("CLEARING ALL SLIDES"); unsafe { self.as_mut().begin_reset_model(); - self.as_mut().slides_mut().clear(); + self.as_mut().rust_mut().slides.clear(); self.as_mut().end_reset_model(); } } @@ -299,7 +310,7 @@ impl qobject::SlideModel { _service_item: &QMap_QString_QVariant, ) { println!("Rusty-Removal-Time: {:?}", index); - let slides = self.slides().clone(); + let slides = self.slides.clone(); let slides_iter = slides.iter(); for (i, slide) in slides_iter.enumerate().rev() { if slide.service_item_id == index { @@ -307,7 +318,7 @@ impl qobject::SlideModel { println!("Removing-slide: {:?}", i); } else if slide.service_item_id > index { if let Some(slide) = - self.as_mut().slides_mut().get_mut(i) + self.as_mut().rust_mut().slides.get_mut(i) { println!("changing-serviceid-of: {:?}", i); println!( @@ -322,7 +333,7 @@ impl qobject::SlideModel { } pub fn remove_item(mut self: Pin<&mut Self>, index: i32) { - if index < 0 || (index as usize) >= self.slides().len() { + if index < 0 || (index as usize) >= self.slides.len() { return; } @@ -332,24 +343,27 @@ impl qobject::SlideModel { index, index, ); - self.as_mut().slides_mut().remove(index as usize); + self.as_mut().rust_mut().slides.remove(index as usize); self.as_mut().end_remove_rows(); } println!("removed-row: {:?}", index); } fn add_slide(mut self: Pin<&mut Self>, slide: &Slide) { - let index = self.as_ref().slides().len() as i32; + let index = self.as_ref().slides.len() as i32; println!("{:?}", slide); let slide = slide.clone(); + let count = self.as_ref().count; + self.as_mut().set_count(count + 1); + unsafe { self.as_mut().begin_insert_rows( &QModelIndex::default(), index, index, ); - self.as_mut().slides_mut().push(slide); + self.as_mut().rust_mut().slides.push(slide); self.as_mut().end_insert_rows(); } let thread = self.qt_thread(); @@ -377,7 +391,10 @@ impl qobject::SlideModel { index, index, ); - self.as_mut().slides_mut().insert(index as usize, slide); + self.as_mut() + .rust_mut() + .slides + .insert(index as usize, slide); self.as_mut().end_insert_rows(); } let thread = self.qt_thread(); @@ -503,7 +520,8 @@ impl qobject::SlideModel { .unwrap_or(false); slide.video_thumbnail = QString::from(""); - let slides_iter = self.as_mut().slides_mut().iter_mut(); + let mut binding = self.as_mut().rust_mut(); + let slides_iter = binding.slides.iter_mut(); let mut slide_index = 0; for (i, slide) in slides_iter.enumerate().rev() { if slide.service_item_id == index { @@ -513,7 +531,7 @@ impl qobject::SlideModel { } // We need to move all the current slides service_item_id's up by one. - let slides_iter = self.as_mut().slides_mut().iter_mut(); + let slides_iter = binding.slides.iter_mut(); for slide in slides_iter.filter(|x| x.service_item_id >= index) { @@ -747,7 +765,7 @@ impl qobject::SlideModel { } let move_down = source_index < destination_index; - let slides = self.slides().clone(); + let slides = self.slides.clone(); let slides_iter = slides.iter(); let mut first_slide = 0; @@ -798,7 +816,7 @@ impl qobject::SlideModel { println!("RUST_dest_slide: {:?}", dest_slide); println!("RUST_len: {:?}", self.rust().slides.len()); - let slides = self.slides().clone(); + let slides = self.slides.clone(); let slides_iter = slides.iter(); unsafe { @@ -824,7 +842,7 @@ impl qobject::SlideModel { }) { if let Some(slide) = - self.as_mut().slides_mut().get_mut(i) + self.as_mut().rust_mut().slides.get_mut(i) { println!( "rust: these ones right here officer. from {:?} to {:?}", @@ -841,7 +859,7 @@ impl qobject::SlideModel { .filter(|x| x.0 < (dest_slide + count) as usize) { if let Some(slide) = - self.as_mut().slides_mut().get_mut(i) + self.as_mut().rust_mut().slides.get_mut(i) { println!( "rust: these ones right here officer. from {:?} to {:?}", @@ -854,7 +872,8 @@ impl qobject::SlideModel { } else { if let Some(slide) = self .as_mut() - .slides_mut() + .rust_mut() + .slides .get_mut(dest_slide as usize) { println!( @@ -873,7 +892,7 @@ impl qobject::SlideModel { .filter(|x| x.1.service_item_id >= source_index) { if let Some(slide) = - self.as_mut().slides_mut().get_mut(i) + self.as_mut().rust_mut().slides.get_mut(i) { println!( "rust-switching-service: {:?} to {:?}", @@ -894,7 +913,7 @@ impl qobject::SlideModel { .filter(|x| x.1.service_item_id <= source_index) { if let Some(slide) = - self.as_mut().slides_mut().get_mut(i) + self.as_mut().rust_mut().slides.get_mut(i) { println!( "rust-switching-service-of: {:?} to {:?}", @@ -929,12 +948,14 @@ impl qobject::SlideModel { let move_amount = dest_index - source_index - count + 1; // println!("rust-move_amount: {:?}", move_amount); - self.as_mut().slides_mut()[source_index..=dest_index] + self.as_mut().rust_mut().slides + [source_index..=dest_index] .rotate_right(move_amount); } else { let move_amount = end_slide - dest_index - count + 1; println!("rust-move_amount: {:?}", move_amount); - self.as_mut().slides_mut()[dest_index..=end_slide] + self.as_mut().rust_mut().slides + [dest_index..=end_slide] .rotate_left(move_amount); } self.as_mut().end_reset_model(); @@ -968,17 +989,17 @@ impl qobject::SlideModel { self: Pin<&mut Self>, index: i32, ) -> i32 { - let slides = self.slides().clone(); + let slides = self.slides.clone(); let slides_iter = slides.iter(); debug!(service_item = index, "Getting slide from this item"); let mut id = 0; - for (i, slide) in slides_iter + if let Some((i, slide)) = slides_iter .enumerate() .filter(|(i, slide)| slide.service_item_id == index) + .next() { debug!(slide_id = i, ?slide); id = i as i32; - break; } id } @@ -988,13 +1009,13 @@ impl qobject::SlideModel { let tl = &self.as_ref().index(0, 0, &QModelIndex::default()); let br = &self.as_ref().index(rc, 0, &QModelIndex::default()); let mut vector_roles = QVector_i32::default(); - vector_roles.append(self.get_role(Role::ActiveRole)); - for slide in self.as_mut().slides_mut().iter_mut() { + vector_roles.append(self.get_role(SlideRoles::Active)); + for slide in self.as_mut().rust_mut().slides.iter_mut() { // println!("slide is deactivating {:?}", i); slide.active = false; } if let Some(slide) = - self.as_mut().slides_mut().get_mut(index as usize) + self.as_mut().rust_mut().slides.get_mut(index as usize) { debug!( slide = index, @@ -1012,83 +1033,79 @@ impl qobject::SlideModel { // slide.video_background // ); slide.active = true; - self.as_mut().emit_data_changed(tl, br, &vector_roles); + self.as_mut().data_changed(tl, br, &vector_roles); // We use this signal generated by our signals enum to tell QML that // the active slide has changed which is used to reposition views. - self.as_mut().emit_active_changed(&index); + self.as_mut().active_change(&index); true } else { false } } - fn get_role(&self, role: Role) -> i32 { + fn get_role(&self, role: SlideRoles) -> i32 { match role { - Role::TextRole => 1, - Role::ActiveRole => 12, - Role::SelectedRole => 13, - Role::LoopingRole => 14, - Role::VideoThumbnailRole => 15, - Role::VideoStartTimeRole => 16, - Role::VideoEndTimeRole => 17, + SlideRoles::Text => 1, + SlideRoles::Active => 12, + SlideRoles::Selected => 13, + SlideRoles::Looping => 14, + SlideRoles::VideoThumbnail => 15, + SlideRoles::VideoStartTime => 16, + SlideRoles::VideoEndTime => 17, _ => 0, } } } // QAbstractListModel implementation -impl qobject::SlideModel { +impl slide_model::SlideModel { pub fn data(&self, index: &QModelIndex, role: i32) -> QVariant { - let role = qobject::Roles { repr: role }; - if let Some(slide) = self.slides().get(index.row() as usize) { + let role = SlideRoles { repr: role }; + if let Some(slide) = self.slides.get(index.row() as usize) { return match role { - qobject::Roles::Ty => QVariant::from(&slide.ty), - qobject::Roles::Text => QVariant::from(&slide.text), - qobject::Roles::Audio => QVariant::from(&slide.audio), - qobject::Roles::ImageBackground => { + SlideRoles::Ty => QVariant::from(&slide.ty), + SlideRoles::Text => QVariant::from(&slide.text), + SlideRoles::Audio => QVariant::from(&slide.audio), + SlideRoles::ImageBackground => { QVariant::from(&slide.image_background) } - qobject::Roles::VideoBackground => { + SlideRoles::VideoBackground => { QVariant::from(&slide.video_background) } - qobject::Roles::HTextAlignment => { + SlideRoles::HTextAlignment => { QVariant::from(&slide.htext_alignment) } - qobject::Roles::VTextAlignment => { + SlideRoles::VTextAlignment => { QVariant::from(&slide.vtext_alignment) } - qobject::Roles::Font => QVariant::from(&slide.font), - qobject::Roles::FontSize => { + SlideRoles::Font => QVariant::from(&slide.font), + SlideRoles::FontSize => { QVariant::from(&slide.font_size) } - qobject::Roles::ServiceItemId => { + SlideRoles::ServiceItemId => { QVariant::from(&slide.service_item_id) } - qobject::Roles::SlideIndex => { + SlideRoles::SlideIndex => { QVariant::from(&slide.slide_index) } - qobject::Roles::SlideCount => { + SlideRoles::SlideCount => { QVariant::from(&slide.slide_count) } - qobject::Roles::Active => { - QVariant::from(&slide.active) - } - qobject::Roles::Selected => { + SlideRoles::Active => QVariant::from(&slide.active), + SlideRoles::Selected => { QVariant::from(&slide.selected) } - qobject::Roles::Looping => { - QVariant::from(&slide.looping) - } - qobject::Roles::VideoThumbnail => { + SlideRoles::Looping => QVariant::from(&slide.looping), + SlideRoles::VideoThumbnail => { QVariant::from(&slide.video_thumbnail) } - qobject::Roles::VideoStartTime => { + SlideRoles::VideoStartTime => { QVariant::from(&slide.video_start_time) } - qobject::Roles::VideoEndTime => { + SlideRoles::VideoEndTime => { QVariant::from(&slide.video_end_time) } - qobject::Roles::Html => QVariant::from(&slide.html), + SlideRoles::Html => QVariant::from(&slide.html), _ => QVariant::default(), }; } @@ -1096,89 +1113,77 @@ impl qobject::SlideModel { QVariant::default() } - // Example of overriding a C++ virtual method and calling the base class implementation. - pub fn can_fetch_more(&self, parent: &QModelIndex) -> bool { - self.base_can_fetch_more(parent) - } + // // Example of overriding a C++ virtual method and calling the base class implementation. + // pub fn can_fetch_more(&self, parent: &QModelIndex) -> bool { + // self.base_can_fetch_more(parent) + // } pub fn role_names(&self) -> QHash_i32_QByteArray { let mut roles = QHash_i32_QByteArray::default(); + roles.insert(SlideRoles::Ty.repr, QByteArray::from("type")); + roles.insert(SlideRoles::Text.repr, QByteArray::from("text")); roles.insert( - qobject::Roles::Ty.repr, - cxx_qt_lib::QByteArray::from("type"), + SlideRoles::Audio.repr, + QByteArray::from("audio"), ); roles.insert( - qobject::Roles::Text.repr, - cxx_qt_lib::QByteArray::from("text"), + SlideRoles::ImageBackground.repr, + QByteArray::from("imageBackground"), ); roles.insert( - qobject::Roles::Audio.repr, - cxx_qt_lib::QByteArray::from("audio"), + SlideRoles::VideoBackground.repr, + QByteArray::from("videoBackground"), ); roles.insert( - qobject::Roles::ImageBackground.repr, - cxx_qt_lib::QByteArray::from("imageBackground"), + SlideRoles::HTextAlignment.repr, + QByteArray::from("hTextAlignment"), ); roles.insert( - qobject::Roles::VideoBackground.repr, - cxx_qt_lib::QByteArray::from("videoBackground"), + SlideRoles::VTextAlignment.repr, + QByteArray::from("vTextAlignment"), + ); + roles.insert(SlideRoles::Font.repr, QByteArray::from("font")); + roles.insert( + SlideRoles::FontSize.repr, + QByteArray::from("fontSize"), ); roles.insert( - qobject::Roles::HTextAlignment.repr, - cxx_qt_lib::QByteArray::from("hTextAlignment"), + SlideRoles::ServiceItemId.repr, + QByteArray::from("serviceItemId"), ); roles.insert( - qobject::Roles::VTextAlignment.repr, - cxx_qt_lib::QByteArray::from("vTextAlignment"), + SlideRoles::SlideIndex.repr, + QByteArray::from("slideIndex"), ); roles.insert( - qobject::Roles::Font.repr, - cxx_qt_lib::QByteArray::from("font"), + SlideRoles::SlideCount.repr, + QByteArray::from("imageCount"), ); roles.insert( - qobject::Roles::FontSize.repr, - cxx_qt_lib::QByteArray::from("fontSize"), + SlideRoles::Active.repr, + QByteArray::from("active"), ); roles.insert( - qobject::Roles::ServiceItemId.repr, - cxx_qt_lib::QByteArray::from("serviceItemId"), + SlideRoles::Selected.repr, + QByteArray::from("selected"), ); roles.insert( - qobject::Roles::SlideIndex.repr, - cxx_qt_lib::QByteArray::from("slideIndex"), + SlideRoles::Looping.repr, + QByteArray::from("looping"), ); roles.insert( - qobject::Roles::ImageCount.repr, - cxx_qt_lib::QByteArray::from("imageCount"), + SlideRoles::VideoThumbnail.repr, + QByteArray::from("videoThumbnail"), ); roles.insert( - qobject::Roles::Active.repr, - cxx_qt_lib::QByteArray::from("active"), + SlideRoles::VideoStartTime.repr, + QByteArray::from("videoStartTime"), ); roles.insert( - qobject::Roles::Selected.repr, - cxx_qt_lib::QByteArray::from("selected"), - ); - roles.insert( - qobject::Roles::Looping.repr, - cxx_qt_lib::QByteArray::from("looping"), - ); - roles.insert( - qobject::Roles::VideoThumbnail.repr, - cxx_qt_lib::QByteArray::from("videoThumbnail"), - ); - roles.insert( - qobject::Roles::VideoStartTime.repr, - cxx_qt_lib::QByteArray::from("videoStartTime"), - ); - roles.insert( - qobject::Roles::VideoEndTime.repr, - cxx_qt_lib::QByteArray::from("videoEndTime"), - ); - roles.insert( - qobject::Roles::Html.repr, - cxx_qt_lib::QByteArray::from("html"), + SlideRoles::VideoEndTime.repr, + QByteArray::from("videoEndTime"), ); + roles.insert(SlideRoles::Html.repr, QByteArray::from("html")); roles } @@ -1187,8 +1192,4 @@ impl qobject::SlideModel { // println!("row count is {cnt}"); cnt } - - pub fn count(&self) -> i32 { - self.rust().slides.len() as i32 - } } diff --git a/src/rust/slide_object.rs b/src/rust/slide_object.rs index 739d274..e7daf1f 100644 --- a/src/rust/slide_object.rs +++ b/src/rust/slide_object.rs @@ -51,7 +51,7 @@ mod slide_object { #[qproperty(QString, vtext_alignment)] #[qproperty(QString, htext_alignment)] #[qproperty(QString, font)] - #[qproperty(bool, font_size)] + #[qproperty(i32, font_size)] #[qproperty(f32, video_start_time)] #[qproperty(f32, video_end_time)] type SlideObject = super::SlideObjectRust; @@ -81,8 +81,14 @@ mod slide_object { } } +use std::pin::Pin; + +use cxx_qt::CxxQtType; +use cxx_qt_lib::{QString, QVariant}; use tracing::debug; +use self::slide_object::QMap_QString_QVariant; + #[derive(Clone, Debug)] pub struct SlideObjectRust { slide_index: i32, @@ -128,7 +134,7 @@ impl Default for SlideObjectRust { } } -impl qobject::SlideObject { +impl slide_object::SlideObject { pub fn change_slide( mut self: Pin<&mut Self>, item: QMap_QString_QVariant, @@ -153,12 +159,12 @@ impl qobject::SlideObject { debug!(?html, count, slide_index); if slide_index > 0 && slide_index < count - 1 { if current_index < &index { - self.as_mut().emit(Signals::RevealNext); - debug!(signal = ?Signals::RevealNext); + self.as_mut().reveal_next(); + debug!("RevealNext"); return; } else if slide_index > 0 { - self.as_mut().emit(Signals::RevealPrev); - debug!(signal = ?Signals::RevealPrev); + self.as_mut().reveal_prev(); + debug!("RevealPrev"); return; } } @@ -267,9 +273,9 @@ impl qobject::SlideObject { .get(&QString::from("fontSize")) .unwrap_or(QVariant::from(&50)); if let Some(font_size) = font_size.value::() { - if &font_size != self.as_ref().font_size() { + if font_size != self.as_ref().font_size { println!("font-size: {font_size}"); - self.as_mut().set_font_size(font_size); + self.as_mut().rust_mut().font_size = font_size; } } else { println!("font-size: empty"); @@ -282,8 +288,7 @@ impl qobject::SlideObject { println!("looping: {looping}"); self.as_mut().set_looping(looping); let lp = looping; - self.as_mut() - .emit(Signals::LoopChanged { looping: &lp }); + self.as_mut().loop_changed(lp) } } else { println!("looping: empty") @@ -308,7 +313,8 @@ impl qobject::SlideObject { self.as_mut().set_slide_index(slide_index); - self.as_mut().emit(Signals::SlideChanged { slide: &index }); + self.as_mut().slide_changed(index); + // self.as_mut().emit(Signals::SlideChanged { slide: &index }); println!("## Slide End ##"); } @@ -330,12 +336,12 @@ impl qobject::SlideObject { } pub fn play(mut self: Pin<&mut Self>) -> bool { self.as_mut().set_is_playing(true); - self.as_mut().emit_playing_changed(&true); + self.as_mut().playing_changed(true); true } pub fn pause(mut self: Pin<&mut Self>) -> bool { self.as_mut().set_is_playing(false); - self.as_mut().emit_playing_changed(&false); + self.as_mut().playing_changed(false); false } pub fn play_pause(mut self: Pin<&mut Self>) -> bool { @@ -344,7 +350,7 @@ impl qobject::SlideObject { true => self.as_mut().set_is_playing(false), false => self.as_mut().set_is_playing(true), } - self.as_mut().emit_playing_changed(&!playing); + self.as_mut().playing_changed(!playing); !playing } } diff --git a/src/rust/songs/song_editor.rs b/src/rust/songs/song_editor.rs index 3b97c66..dbaf184 100644 --- a/src/rust/songs/song_editor.rs +++ b/src/rust/songs/song_editor.rs @@ -1,9 +1,5 @@ #[cxx_qt::bridge] pub mod song_editor { - use std::path::PathBuf; - - use tracing::{debug, debug_span, error, info, instrument}; - unsafe extern "C++" { include!("cxx-qt-lib/qmap.h"); type QMap_QString_QVariant = @@ -22,108 +18,119 @@ pub mod song_editor { // type CxxSongs = crate::songs::song_model::qobject::SongModel; } - #[derive(Clone, Debug)] - #[cxx_qt::qobject] - pub struct SongEditor { - #[qproperty] - title: QString, - #[qproperty] - lyrics: QString, - #[qproperty] - author: QString, - #[qproperty] - ccli: QString, - #[qproperty] - audio: QString, - #[qproperty] - verse_order: QString, - #[qproperty] - verse_order_error: bool, - #[qproperty] - background: QString, - #[qproperty] - background_type: QString, - #[qproperty] - horizontal_text_alignment: QString, - #[qproperty] - vertical_text_alignment: QString, - #[qproperty] - font: QString, - #[qproperty] - font_size: i32, - #[qproperty] - background_exists: bool, - #[qproperty] - audio_exists: bool, - // #[qproperty] - // song_model: *mut CxxSongs, - } - - impl Default for SongEditor { - fn default() -> Self { - Self { - title: QString::default(), - lyrics: QString::default(), - author: QString::default(), - ccli: QString::default(), - audio: QString::default(), - verse_order: QString::default(), - verse_order_error: false, - background: QString::default(), - background_type: QString::default(), - horizontal_text_alignment: QString::default(), - vertical_text_alignment: QString::default(), - font: QString::default(), - font_size: 50, - background_exists: true, - audio_exists: true, - // song_model: std::ptr::null_mut(), - } - } - } - - impl qobject::SongEditor { - fn idk(mut self: Pin<&mut Self>) { - // let mut model = self.song_model().as_mut().unwrap(); - // let pinned_model = Pin::new_unchecked(model); - // pinned_model.update_ccli(0, QString::from("idk")); - todo!() - } + unsafe extern "RustQt" { + #[qobject] + #[qml_element] + #[qproperty(QString, title)] + #[qproperty(QString, lyrics)] + #[qproperty(QString, author)] + #[qproperty(QString, ccli)] + #[qproperty(QString, audio)] + #[qproperty(QString, verse_order)] + #[qproperty(bool, verse_order_error)] + #[qproperty(QString, background)] + #[qproperty(QString, background_type)] + #[qproperty(QString, horizontal_text_alignment)] + #[qproperty(QString, vertical_text_alignment)] + #[qproperty(QString, font)] + #[qproperty(i32, font_size)] + #[qproperty(bool, background_exists)] + #[qproperty(bool, audio_exists)] + type SongEditor = super::SongEditorRust; #[qinvokable] - pub fn check_verse_order(mut self: Pin<&mut Self>) { - let vo = self.verse_order().to_string(); - let split = vo.split(" "); - debug!(verse_order = ?vo, iterator = ?split); - for s in split { - if s.contains(",") || s.is_empty() { - self.as_mut().set_verse_order_error(true); - } else { - self.as_mut().set_verse_order_error(false); - } - } - } - + fn check_verse_order(self: Pin<&mut SongEditor>); #[qinvokable] - pub fn check_files(mut self: Pin<&mut Self>) { - let background = PathBuf::from( - self.background() - .clone() - .to_string() - .trim_start_matches("file://"), - ); - let audio = PathBuf::from( - self.audio() - .clone() - .to_string() - .trim_start_matches("file://"), - ); - debug!( - background = background.exists(), - audio = audio.exists() - ); - self.as_mut().set_background_exists(background.exists()); - self.as_mut().set_audio_exists(audio.exists()); + fn check_files(self: Pin<&mut SongEditor>); + } +} + +use cxx_qt_lib::QString; +use std::{path::PathBuf, pin::Pin}; +use tracing::{debug, debug_span, error, info, instrument}; + +#[derive(Clone, Debug)] +pub struct SongEditorRust { + title: QString, + lyrics: QString, + author: QString, + ccli: QString, + audio: QString, + verse_order: QString, + verse_order_error: bool, + background: QString, + background_type: QString, + horizontal_text_alignment: QString, + vertical_text_alignment: QString, + font: QString, + font_size: i32, + background_exists: bool, + audio_exists: bool, + // song_model: *mut CxxSongs, +} + +impl Default for SongEditorRust { + fn default() -> Self { + Self { + title: QString::default(), + lyrics: QString::default(), + author: QString::default(), + ccli: QString::default(), + audio: QString::default(), + verse_order: QString::default(), + verse_order_error: false, + background: QString::default(), + background_type: QString::default(), + horizontal_text_alignment: QString::default(), + vertical_text_alignment: QString::default(), + font: QString::default(), + font_size: 50, + background_exists: true, + audio_exists: true, + // song_model: std::ptr::null_mut(), } } } + +impl song_editor::SongEditor { + fn idk(mut self: Pin<&mut Self>) { + // let mut model = self.song_model().as_mut().unwrap(); + // let pinned_model = Pin::new_unchecked(model); + // pinned_model.update_ccli(0, QString::from("idk")); + todo!() + } + + pub fn check_verse_order(mut self: Pin<&mut Self>) { + let vo = self.verse_order().to_string(); + let split = vo.split(" "); + debug!(verse_order = ?vo, iterator = ?split); + for s in split { + if s.contains(",") || s.is_empty() { + self.as_mut().set_verse_order_error(true); + } else { + self.as_mut().set_verse_order_error(false); + } + } + } + + pub fn check_files(mut self: Pin<&mut Self>) { + let background = PathBuf::from( + self.background() + .clone() + .to_string() + .trim_start_matches("file://"), + ); + let audio = PathBuf::from( + self.audio() + .clone() + .to_string() + .trim_start_matches("file://"), + ); + debug!( + background = background.exists(), + audio = audio.exists() + ); + self.as_mut().set_background_exists(background.exists()); + self.as_mut().set_audio_exists(audio.exists()); + } +} diff --git a/src/rust/songs/song_model.rs b/src/rust/songs/song_model.rs index 91751d8..032ce7c 100644 --- a/src/rust/songs/song_model.rs +++ b/src/rust/songs/song_model.rs @@ -1,13 +1,5 @@ #[cxx_qt::bridge] pub mod song_model { - use crate::models::*; - use crate::schema::songs::dsl::*; - use crate::songs::song_model::song_model::Song; - use diesel::sqlite::SqliteConnection; - use diesel::{delete, insert_into, prelude::*, update}; - use std::collections::HashMap; - use tracing::{debug, debug_span, error, info, instrument}; - unsafe extern "C++" { include!(< QAbstractListModel >); include!("cxx-qt-lib/qhash.h"); @@ -30,988 +22,1101 @@ pub mod song_model { type QList_QString = cxx_qt_lib::QList; } - #[derive(Default, Clone, Debug)] - pub struct Song { - id: i32, - title: String, - lyrics: String, - author: String, - ccli: String, - audio: String, - verse_order: String, - background: String, - background_type: String, - horizontal_text_alignment: String, - vertical_text_alignment: String, - font: String, - font_size: i32, + #[qenum(SongModel)] + enum SongRoles { + Id, + Title, + Lyrics, + Author, + Ccli, + Audio, + VerseOrder, + Background, + BackgroundType, + HorizontalTextAlignment, + VerticalTextAlignment, + Font, + FontSize, } - #[cxx_qt::qobject(base = "QAbstractListModel")] - #[derive(Default, Debug)] - pub struct SongModel { - highest_id: i32, - songs: Vec, - } + unsafe extern "RustQt" { + #[qobject] + #[base = "QAbstractListModel"] + #[qml_element] + #[qproperty(i32, count)] + type SongModel = super::SongModelRust; - #[cxx_qt::qsignals(SongModel)] - pub enum Signals<'a> { #[inherit] - DataChanged { - top_left: &'a QModelIndex, - bottom_right: &'a QModelIndex, - roles: &'a QVector_i32, - }, - TitleChanged {}, - FontSizeChanged {}, - BackgroundChanged {}, - } - - enum Role { - IdRole, - TitleRole, - LyricsRole, - AuthorRole, - CcliRole, - AudioRole, - VerseOrderRole, - BackgroundRole, - BackgroundTypeRole, - HorizontalTextAlignmentRole, - VerticalTextAlignmentRole, - FontRole, - FontSizeRole, - } - - impl qobject::SongModel { - #[qinvokable] - pub fn clear(mut self: Pin<&mut Self>) { - unsafe { - self.as_mut().begin_reset_model(); - self.as_mut().songs_mut().clear(); - self.as_mut().end_reset_model(); - } - } + #[qsignal] + fn data_changed( + self: Pin<&mut SongModel>, + top_left: &QModelIndex, + bottom_right: &QModelIndex, + roles: &QVector_i32, + ); + #[qsignal] + fn title_changed(self: Pin<&mut SongModel>); + #[qsignal] + fn font_size_changed(self: Pin<&mut SongModel>); + #[qsignal] + fn background_changed(self: Pin<&mut SongModel>); #[qinvokable] - pub fn setup(mut self: Pin<&mut Self>) { - let db = &mut self.as_mut().get_db(); - run_migrations(db); - - let results = songs - .load::(db) - .expect("NO TABLE?????????????"); - self.as_mut().set_highest_id(0); - - println!("SHOWING SONGS"); - println!("--------------"); - for song in results { - println!("{}", song.title); - println!("{}", song.id); - println!( - "{}", - song.background.clone().unwrap_or_default() - ); - println!("--------------"); - if self.as_mut().highest_id() < &song.id { - self.as_mut().set_highest_id(song.id); - } - - let song = Song { - id: song.id, - title: song.title, - lyrics: song.lyrics.unwrap_or_default(), - author: song.author.unwrap_or_default(), - ccli: song.ccli.unwrap_or_default(), - audio: song.audio.unwrap_or_default(), - verse_order: song.verse_order.unwrap_or_default(), - background: song.background.unwrap_or_default(), - background_type: song - .background_type - .unwrap_or_default(), - horizontal_text_alignment: song - .horizontal_text_alignment - .unwrap_or_default(), - vertical_text_alignment: song - .vertical_text_alignment - .unwrap_or_default(), - font: song.font.unwrap_or_default(), - font_size: song.font_size.unwrap_or_default(), - }; - - self.as_mut().add_song(song); - } - println!("--------------------------------------"); - println!("{:?}", self.as_mut().songs()); - println!("--------------------------------------"); - } - + fn clear(self: Pin<&mut SongModel>); #[qinvokable] - pub fn remove_item( - mut self: Pin<&mut Self>, + fn setup(self: Pin<&mut SongModel>); + #[qinvokable] + fn remove_item(self: Pin<&mut SongModel>, index: i32) + -> bool; + #[qinvokable] + fn new_song(self: Pin<&mut SongModel>) -> bool; + #[qinvokable] + fn get_item( + self: Pin<&mut SongModel>, index: i32, - ) -> bool { - if index < 0 || (index as usize) >= self.songs().len() { - return false; - } - let db = &mut self.as_mut().get_db(); - - let song_id = - self.songs().get(index as usize).unwrap().id; - - let result = - delete(songs.filter(id.eq(song_id))).execute(db); - - match result { - Ok(_i) => { - unsafe { - self.as_mut().begin_remove_rows( - &QModelIndex::default(), - index, - index, - ); - self.as_mut() - .songs_mut() - .remove(index as usize); - self.as_mut().end_remove_rows(); - } - println!("removed-item-at-index: {:?}", song_id); - println!("new-Vec: {:?}", self.as_mut().songs()); - true - } - Err(_e) => { - println!("Cannot connect to database"); - false - } - } - } - - fn get_db(self: Pin<&mut Self>) -> SqliteConnection { - let mut data = dirs::data_local_dir().unwrap(); - data.push("lumina"); - data.push("library-db.sqlite3"); - let mut db_url = String::from("sqlite://"); - db_url.push_str(data.to_str().unwrap()); - println!("DB: {:?}", db_url); - - SqliteConnection::establish(&db_url).unwrap_or_else( - |_| panic!("error connecting to {}", db_url), - ) - } - + ) -> QMap_QString_QVariant; #[qinvokable] - pub fn new_song(mut self: Pin<&mut Self>) -> bool { - let song_id = self.rust().highest_id + 1; - let song_title = String::from("title"); - let db = &mut self.as_mut().get_db(); - - let song = Song { - id: song_id, - title: song_title.clone(), - ..Default::default() - }; - - let result = insert_into(songs) - .values(( - id.eq(&song_id), - title.eq(&song_title), - lyrics.eq(&song.lyrics), - author.eq(&song.author), - ccli.eq(&song.ccli), - audio.eq(&song.audio), - verse_order.eq(&song.verse_order), - background.eq(&song.background), - background_type.eq(&song.background_type), - horizontal_text_alignment - .eq(&song.horizontal_text_alignment), - vertical_text_alignment - .eq(&song.vertical_text_alignment), - font.eq(&song.font), - font_size.eq(&song.font_size), - )) - .execute(db); - println!("{:?}", result); - - match result { - Ok(_i) => { - self.as_mut().add_song(song); - println!("{:?}", self.as_mut().songs()); - true - } - Err(_e) => { - println!("Cannot connect to database"); - false - } - } - } - - fn add_song(mut self: Pin<&mut Self>, song: self::Song) { - let index = self.as_ref().songs().len() as i32; - println!("{:?}", song); - unsafe { - self.as_mut().begin_insert_rows( - &QModelIndex::default(), - index, - index, - ); - self.as_mut().songs_mut().push(song); - self.as_mut().end_insert_rows(); - } - } - - fn get_indices( - mut self: Pin<&mut Self>, - song_id: i32, - role: Role, - ) -> (usize, QModelIndex, QVector_i32) { - let mut vector_roles = QVector_i32::default(); - vector_roles.append(self.as_ref().get_role(role)); - let index = self - .as_ref() - .songs() - .iter() - .position(|x| x.id == song_id) - .unwrap(); - let model_index = self.as_ref().index( - index as i32, - 0, - &QModelIndex::default(), - ); - (index, model_index, vector_roles) - } - + fn get_lyric_list( + self: Pin<&mut SongModel>, + index: i32, + ) -> QStringList; #[qinvokable] - pub fn update_title( - mut self: Pin<&mut Self>, - song_id: i32, - updated_title: QString, - ) -> bool { - let (index, model_index, vector_roles) = - self.as_mut().get_indices(song_id, Role::TitleRole); - let db = &mut self.as_mut().get_db(); - let result = update(songs.filter(id.eq(song_id))) - .set(title.eq(updated_title.to_string())) - .execute(db); - match result { - Ok(_i) => { - debug!(_i, index); - if let Some(song) = - self.as_mut().songs_mut().get_mut(index) - { - debug!(?song); - song.title = updated_title.to_string(); - self.as_mut().emit_data_changed( - &model_index, - &model_index, - &vector_roles, - ); - true - } else { - false - } - } - Err(_e) => false, - } - } - - #[qinvokable] - pub fn update_lyrics( - mut self: Pin<&mut Self>, - song_id: i32, + fn update_lyrics( + self: Pin<&mut SongModel>, + index: i32, updated_lyrics: QString, - ) -> bool { - let (index, model_index, vector_roles) = - self.as_mut().get_indices(song_id, Role::LyricsRole); - let db = &mut self.as_mut().get_db(); - let result = update(songs.filter(id.eq(song_id))) - .set(lyrics.eq(updated_lyrics.to_string())) - .execute(db); - match result { - Ok(_i) => { - if let Some(song) = - self.as_mut().songs_mut().get_mut(index) - { - song.lyrics = updated_lyrics.to_string(); - self.as_mut().emit_data_changed( - &model_index, - &model_index, - &vector_roles, - ); - true - } else { - false - } - } - Err(_e) => false, - } - } - + ) -> bool; #[qinvokable] - pub fn update_author( - mut self: Pin<&mut Self>, - song_id: i32, + fn update_author( + self: Pin<&mut SongModel>, + index: i32, updated_author: QString, - ) -> bool { - let (index, model_index, vector_roles) = - self.as_mut().get_indices(song_id, Role::AuthorRole); - - let db = &mut self.as_mut().get_db(); - let result = update(songs.filter(id.eq(song_id))) - .set(author.eq(updated_author.to_string())) - .execute(db); - match result { - Ok(_i) => { - if let Some(song) = - self.as_mut().songs_mut().get_mut(index) - { - song.author = updated_author.to_string(); - self.as_mut().emit_data_changed( - &model_index, - &model_index, - &vector_roles, - ); - true - } else { - false - } - } - Err(_e) => false, - } - } - + ) -> bool; #[qinvokable] - pub fn update_audio( - mut self: Pin<&mut Self>, - song_id: i32, - updated_audio: QString, - ) -> bool { - let (index, model_index, vector_roles) = - self.as_mut().get_indices(song_id, Role::AudioRole); - - let db = &mut self.as_mut().get_db(); - let result = update(songs.filter(id.eq(song_id))) - .set(audio.eq(updated_audio.to_string())) - .execute(db); - match result { - Ok(_i) => { - if let Some(song) = - self.as_mut().songs_mut().get_mut(index) - { - song.audio = updated_audio.to_string(); - self.as_mut().emit_data_changed( - &model_index, - &model_index, - &vector_roles, - ); - true - } else { - false - } - } - Err(_e) => false, - } - } - + fn update_title( + self: Pin<&mut SongModel>, + index: i32, + updated_title: QString, + ) -> bool; #[qinvokable] - pub fn update_ccli( - mut self: Pin<&mut Self>, - song_id: i32, + fn update_ccli( + self: Pin<&mut SongModel>, + index: i32, updated_ccli: QString, - ) -> bool { - let (index, model_index, vector_roles) = - self.as_mut().get_indices(song_id, Role::CcliRole); - - let db = &mut self.as_mut().get_db(); - let result = update(songs.filter(id.eq(song_id))) - .set(ccli.eq(updated_ccli.to_string())) - .execute(db); - match result { - Ok(_i) => { - if let Some(song) = - self.as_mut().songs_mut().get_mut(index) - { - song.ccli = updated_ccli.to_string(); - self.as_mut().emit_data_changed( - &model_index, - &model_index, - &vector_roles, - ); - true - } else { - false - } - } - Err(_e) => false, - } - } - + ) -> bool; #[qinvokable] - pub fn update_verse_order( - mut self: Pin<&mut Self>, - song_id: i32, + fn update_verse_order( + self: Pin<&mut SongModel>, + index: i32, updated_verse_order: QString, - ) -> bool { - let (index, model_index, vector_roles) = self - .as_mut() - .get_indices(song_id, Role::VerseOrderRole); - - let db = &mut self.as_mut().get_db(); - let result = update(songs.filter(id.eq(song_id))) - .set(verse_order.eq(updated_verse_order.to_string())) - .execute(db); - match result { - Ok(_i) => { - if let Some(song) = - self.as_mut().songs_mut().get_mut(index) - { - song.verse_order = - updated_verse_order.to_string(); - self.as_mut().emit_data_changed( - &model_index, - &model_index, - &vector_roles, - ); - true - } else { - false - } - } - Err(_e) => false, - } - } - + ) -> bool; #[qinvokable] - pub fn update_background( - mut self: Pin<&mut Self>, - song_id: i32, + fn update_background( + self: Pin<&mut SongModel>, + index: i32, updated_background: QString, - ) -> bool { - let (index, model_index, vector_roles) = self - .as_mut() - .get_indices(song_id, Role::BackgroundRole); - - let db = &mut self.as_mut().get_db(); - let result = update(songs.filter(id.eq(song_id))) - .set(background.eq(updated_background.to_string())) - .execute(db); - match result { - Ok(_i) => { - if let Some(song) = - self.as_mut().songs_mut().get_mut(index) - { - song.background = - updated_background.to_string(); - debug!( - background = ?updated_background, - model_index = ?model_index, - roles = vector_roles.get(0) - ); - self.as_mut().emit_data_changed( - &model_index, - &model_index, - &vector_roles, - ); - self.as_mut().emit_background_changed(); - true - } else { - false - } - } - Err(_e) => false, - } - } - + ) -> bool; #[qinvokable] - pub fn update_background_type( - mut self: Pin<&mut Self>, - song_id: i32, + fn update_background_type( + self: Pin<&mut SongModel>, + index: i32, updated_background_type: QString, - ) -> bool { - let (index, model_index, vector_roles) = self - .as_mut() - .get_indices(song_id, Role::BackgroundTypeRole); - - let db = &mut self.as_mut().get_db(); - let result = update(songs.filter(id.eq(song_id))) - .set( - background_type - .eq(updated_background_type.to_string()), - ) - .execute(db); - match result { - Ok(_i) => { - if let Some(song) = - self.as_mut().songs_mut().get_mut(index) - { - song.background_type = - updated_background_type.to_string(); - self.as_mut().emit_data_changed( - &model_index, - &model_index, - &vector_roles, - ); - true - } else { - false - } - } - Err(_e) => false, - } - } - + ) -> bool; #[qinvokable] - pub fn update_horizontal_text_alignment( - mut self: Pin<&mut Self>, - song_id: i32, + fn update_horizontal_text_alignment( + self: Pin<&mut SongModel>, + index: i32, updated_horizontal_text_alignment: QString, - ) -> bool { - let (index, model_index, vector_roles) = - self.as_mut().get_indices( - song_id, - Role::HorizontalTextAlignmentRole, - ); - - let db = &mut self.as_mut().get_db(); - let result = update(songs.filter(id.eq(song_id))) - .set(horizontal_text_alignment.eq( - updated_horizontal_text_alignment.to_string(), - )) - .execute(db); - match result { - Ok(_i) => { - if let Some(song) = - self.as_mut().songs_mut().get_mut(index) - { - song.horizontal_text_alignment = - updated_horizontal_text_alignment - .to_string(); - self.as_mut().emit_data_changed( - &model_index, - &model_index, - &vector_roles, - ); - true - } else { - false - } - } - Err(_e) => false, - } - } - + ) -> bool; #[qinvokable] - pub fn update_vertical_text_alignment( - mut self: Pin<&mut Self>, - song_id: i32, + fn update_vertical_text_alignment( + self: Pin<&mut SongModel>, + index: i32, updated_vertical_text_alignment: QString, - ) -> bool { - let (index, model_index, vector_roles) = - self.as_mut().get_indices( - song_id, - Role::VerticalTextAlignmentRole, - ); - - let db = &mut self.as_mut().get_db(); - let result = - update(songs.filter(id.eq(song_id))) - .set(vertical_text_alignment.eq( - updated_vertical_text_alignment.to_string(), - )) - .execute(db); - match result { - Ok(_i) => { - if let Some(song) = - self.as_mut().songs_mut().get_mut(index) - { - song.vertical_text_alignment = - updated_vertical_text_alignment - .to_string(); - self.as_mut().emit_data_changed( - &model_index, - &model_index, - &vector_roles, - ); - true - } else { - false - } - } - Err(_e) => false, - } - } - + ) -> bool; #[qinvokable] - pub fn update_font( - mut self: Pin<&mut Self>, - song_id: i32, + fn update_font( + self: Pin<&mut SongModel>, + index: i32, updated_font: QString, - ) -> bool { - let (index, model_index, vector_roles) = - self.as_mut().get_indices(song_id, Role::FontRole); - - let db = &mut self.as_mut().get_db(); - let result = update(songs.filter(id.eq(song_id))) - .set(font.eq(updated_font.to_string())) - .execute(db); - match result { - Ok(_i) => { - if let Some(song) = - self.as_mut().songs_mut().get_mut(index) - { - song.font = updated_font.to_string(); - debug!(?updated_font); - self.as_mut().emit_data_changed( - &model_index, - &model_index, - &vector_roles, - ); - true - } else { - false - } - } - Err(_e) => false, - } - } - + ) -> bool; #[qinvokable] - pub fn update_font_size( - mut self: Pin<&mut Self>, - song_id: i32, + fn update_font_size( + self: Pin<&mut SongModel>, + index: i32, updated_font_size: i32, - ) -> bool { - let (index, model_index, vector_roles) = self - .as_mut() - .get_indices(song_id, Role::FontSizeRole); - - let db = &mut self.as_mut().get_db(); - let result = update(songs.filter(id.eq(song_id))) - .set(font_size.eq(updated_font_size)) - .execute(db); - match result { - Ok(_i) => { - if let Some(song) = - self.as_mut().songs_mut().get_mut(index) - { - song.font_size = updated_font_size; - self.as_mut().emit_data_changed( - &model_index, - &model_index, - &vector_roles, - ); - true - } else { - false - } - } - Err(_e) => false, - } - } - + ) -> bool; #[qinvokable] - pub fn get_item( - self: Pin<&mut Self>, + fn update_audio( + self: Pin<&mut SongModel>, index: i32, - ) -> QMap_QString_QVariant { - debug!(index); - let mut qvariantmap = QMap_QString_QVariant::default(); - let idx = self.index(index, 0, &QModelIndex::default()); - if !idx.is_valid() { - return qvariantmap; - } - let role_names = self.as_ref().role_names(); - let role_names_iter = role_names.iter(); - if let Some(song) = self.rust().songs.get(index as usize) - { - debug!(?song); - for i in role_names_iter { - qvariantmap.insert( - QString::from(&i.1.to_string()), - self.as_ref().data(&idx, *i.0), - ); - } - }; - qvariantmap - } - - #[qinvokable] - pub fn get_lyric_list( - mut self: Pin<&mut Self>, - index: i32, - ) -> QStringList { - println!("LYRIC_LIST: {index}"); - let mut lyric_list = QList_QString::default(); - let idx = self.index(index, 0, &QModelIndex::default()); - if !idx.is_valid() { - return QStringList::default(); - } - if let Some(song) = self.rust().songs.get(index as usize) - { - if song.lyrics.is_empty() { - return QStringList::default(); - } - let raw_lyrics = song.lyrics.clone(); - println!("raw-lyrics: {:?}", raw_lyrics); - let vorder: Vec<&str> = - song.verse_order.split(' ').collect(); - let keywords = vec![ - "Verse 1", "Verse 2", "Verse 3", "Verse 4", - "Verse 5", "Verse 6", "Verse 7", "Verse 8", - "Chorus 1", "Chorus 2", "Chorus 3", "Chorus 4", - "Bridge 1", "Bridge 2", "Bridge 3", "Bridge 4", - "Intro 1", "Intro 2", "Ending 1", "Ending 2", - "Other 1", "Other 2", "Other 3", "Other 4", - ]; - let mut first_item = true; - - let mut lyric_map = HashMap::new(); - let mut verse_title = String::from(""); - let mut lyric = String::from(""); - for (i, line) in raw_lyrics.split("\n").enumerate() { - if keywords.contains(&line) { - if i != 0 { - println!("{verse_title}"); - println!("{lyric}"); - lyric_map.insert(verse_title, lyric); - lyric = String::from(""); - verse_title = line.to_string(); - // println!("{line}"); - // println!("\n"); - } else { - verse_title = line.to_string(); - // println!("{line}"); - // println!("\n"); - } - } else { - lyric.push_str(line); - lyric.push_str("\n"); - } - } - lyric_map.insert(verse_title, lyric); - println!("da-map: {:?}", lyric_map); - - for mut verse in vorder { - let mut verse_name = ""; - debug!(verse = verse); - for word in keywords.clone() { - let end_verse = - verse.get(1..2).unwrap_or_default(); - let beg_verse = - verse.get(0..1).unwrap_or_default(); - println!( - "verse: {:?}, beginning: {:?}, end: {:?}, word: {:?}", - verse, beg_verse, end_verse, word - ); - if word.starts_with(beg_verse) - && word.ends_with(end_verse) - { - verse_name = word; - println!("TITLE: {verse_name}"); - continue; - } - } - if let Some(lyric) = lyric_map.get(verse_name) { - if lyric.contains("\n\n") { - let split_lyrics: Vec<&str> = - lyric.split("\n\n").collect(); - for lyric in split_lyrics { - if lyric == "" { - continue; - } - lyric_list - .append(QString::from(lyric)); - } - continue; - } - lyric_list.append(QString::from(lyric)); - } else { - println!("NOT WORKING!"); - }; - } - for lyric in lyric_list.iter() { - println!("da-list: {:?}", lyric); - } - } - QStringList::from(&lyric_list) - } - - fn get_role(&self, role: Role) -> i32 { - match role { - Role::IdRole => 0, - Role::TitleRole => 1, - Role::LyricsRole => 2, - Role::AuthorRole => 3, - Role::CcliRole => 4, - Role::AudioRole => 5, - Role::VerseOrderRole => 6, - Role::BackgroundRole => 7, - Role::BackgroundTypeRole => 8, - Role::HorizontalTextAlignmentRole => 9, - Role::VerticalTextAlignmentRole => 10, - Role::FontRole => 11, - Role::FontSizeRole => 12, - _ => 0, - } - } + updated_audio: QString, + ) -> bool; } - // Create Rust bindings for C++ functions of the base class (QAbstractItemModel) - #[cxx_qt::inherit] - extern "C++" { + impl cxx_qt::Threading for SongModel {} + + unsafe extern "RustQt" { + #[inherit] unsafe fn begin_insert_rows( - self: Pin<&mut qobject::SongModel>, + self: Pin<&mut SongModel>, parent: &QModelIndex, first: i32, last: i32, ); - unsafe fn end_insert_rows(self: Pin<&mut qobject::SongModel>); + #[inherit] + unsafe fn end_insert_rows(self: Pin<&mut SongModel>); + + #[inherit] unsafe fn begin_remove_rows( - self: Pin<&mut qobject::SongModel>, + self: Pin<&mut SongModel>, parent: &QModelIndex, first: i32, last: i32, ); - unsafe fn end_remove_rows(self: Pin<&mut qobject::SongModel>); - unsafe fn begin_reset_model( - self: Pin<&mut qobject::SongModel>, - ); - unsafe fn end_reset_model(self: Pin<&mut qobject::SongModel>); - } + #[inherit] + unsafe fn begin_move_rows( + self: Pin<&mut SongModel>, + source_parent: &QModelIndex, + source_first: i32, + source_last: i32, + destination_parent: &QModelIndex, + destination_child: i32, + ) -> bool; - #[cxx_qt::inherit] - unsafe extern "C++" { - #[cxx_name = "canFetchMore"] - fn base_can_fetch_more( - self: &qobject::SongModel, + #[inherit] + unsafe fn end_move_rows(self: Pin<&mut SongModel>); + + #[inherit] + unsafe fn end_remove_rows(self: Pin<&mut SongModel>); + + #[inherit] + unsafe fn begin_reset_model(self: Pin<&mut SongModel>); + + #[inherit] + unsafe fn end_reset_model(self: Pin<&mut SongModel>); + + #[inherit] + fn can_fetch_more( + self: &SongModel, parent: &QModelIndex, ) -> bool; + #[inherit] fn index( - self: &qobject::SongModel, + self: &SongModel, row: i32, column: i32, parent: &QModelIndex, ) -> QModelIndex; - } - - // QAbstractListModel implementation - impl qobject::SongModel { - #[qinvokable(cxx_override)] - fn data(&self, index: &QModelIndex, role: i32) -> QVariant { - if let Some(song) = self.songs().get(index.row() as usize) - { - return match role { - 0 => QVariant::from(&song.id), - 1 => QVariant::from(&QString::from(&song.title)), - 2 => QVariant::from(&QString::from(&song.lyrics)), - 3 => QVariant::from(&QString::from(&song.author)), - 4 => QVariant::from(&QString::from(&song.ccli)), - 5 => QVariant::from(&QString::from(&song.audio)), - 6 => QVariant::from(&QString::from( - &song.verse_order, - )), - 7 => QVariant::from(&QString::from( - &song.background, - )), - 8 => QVariant::from(&QString::from( - &song.background_type, - )), - 9 => QVariant::from(&QString::from( - &song.horizontal_text_alignment, - )), - 10 => QVariant::from(&QString::from( - &song.vertical_text_alignment, - )), - 11 => QVariant::from(&QString::from(&song.font)), - 12 => QVariant::from(&song.font_size), - _ => QVariant::default(), - }; - } - - QVariant::default() - } - - // Example of overriding a C++ virtual method and calling the base class implementation. - #[qinvokable(cxx_override)] - pub fn can_fetch_more(&self, parent: &QModelIndex) -> bool { - self.base_can_fetch_more(parent) - } - - #[qinvokable(cxx_override)] - pub fn role_names(&self) -> QHash_i32_QByteArray { - let mut roles = QHash_i32_QByteArray::default(); - roles.insert(0, cxx_qt_lib::QByteArray::from("id")); - roles.insert(1, cxx_qt_lib::QByteArray::from("title")); - roles.insert(2, cxx_qt_lib::QByteArray::from("lyrics")); - roles.insert(3, cxx_qt_lib::QByteArray::from("author")); - roles.insert(4, cxx_qt_lib::QByteArray::from("ccli")); - roles.insert(5, cxx_qt_lib::QByteArray::from("audio")); - roles.insert(6, cxx_qt_lib::QByteArray::from("vorder")); - roles.insert( - 7, - cxx_qt_lib::QByteArray::from("background"), - ); - roles.insert( - 8, - cxx_qt_lib::QByteArray::from("backgroundType"), - ); - roles.insert( - 9, - cxx_qt_lib::QByteArray::from( - "horizontalTextAlignment", - ), - ); - roles.insert( - 10, - cxx_qt_lib::QByteArray::from("verticalTextAlignment"), - ); - roles.insert(11, cxx_qt_lib::QByteArray::from("font")); - roles - .insert(12, cxx_qt_lib::QByteArray::from("fontSize")); - roles - } - - #[qinvokable(cxx_override)] - pub fn row_count(&self, _parent: &QModelIndex) -> i32 { - let cnt = self.rust().songs.len() as i32; - // println!("row count is {cnt}"); - cnt - } #[qinvokable] - pub fn count(&self) -> i32 { - self.rust().songs.len() as i32 + #[cxx_override] + fn data( + self: &SongModel, + index: &QModelIndex, + role: i32, + ) -> QVariant; + + #[qinvokable] + #[cxx_override] + fn role_names(self: &SongModel) -> QHash_i32_QByteArray; + + #[qinvokable] + #[cxx_override] + fn row_count(self: &SongModel, _parent: &QModelIndex) -> i32; + } +} + +use crate::models::*; +use crate::schema::songs::dsl::*; +use crate::songs::song_editor::song_editor::QList_QString; +use cxx_qt::CxxQtType; +use cxx_qt_lib::{ + QByteArray, QModelIndex, QString, QStringList, QVariant, +}; +use diesel::sqlite::SqliteConnection; +use diesel::{delete, insert_into, prelude::*, update}; +use std::collections::HashMap; +use std::pin::Pin; +use tracing::{debug, debug_span, error, info, instrument}; + +use self::song_model::{ + QHash_i32_QByteArray, QMap_QString_QVariant, QVector_i32, + SongRoles, +}; + +#[derive(Default, Clone, Debug)] +pub struct Song { + id: i32, + title: String, + lyrics: String, + author: String, + ccli: String, + audio: String, + verse_order: String, + background: String, + background_type: String, + horizontal_text_alignment: String, + vertical_text_alignment: String, + font: String, + font_size: i32, +} + +#[derive(Default, Debug)] +pub struct SongModelRust { + count: i32, + highest_id: i32, + songs: Vec, +} + +impl song_model::SongModel { + pub fn clear(mut self: Pin<&mut Self>) { + unsafe { + self.as_mut().begin_reset_model(); + self.as_mut().rust_mut().songs.clear(); + self.as_mut().end_reset_model(); + } + } + + pub fn setup(mut self: Pin<&mut Self>) { + let db = &mut self.as_mut().get_db(); + run_migrations(db); + + let results = songs + .load::(db) + .expect("NO TABLE?????????????"); + self.as_mut().rust_mut().highest_id = 0; + + println!("SHOWING SONGS"); + println!("--------------"); + for song in results { + println!("{}", song.title); + println!("{}", song.id); + println!( + "{}", + song.background.clone().unwrap_or_default() + ); + println!("--------------"); + if self.as_mut().highest_id < song.id { + self.as_mut().rust_mut().highest_id = song.id; + } + + let song = Song { + id: song.id, + title: song.title, + lyrics: song.lyrics.unwrap_or_default(), + author: song.author.unwrap_or_default(), + ccli: song.ccli.unwrap_or_default(), + audio: song.audio.unwrap_or_default(), + verse_order: song.verse_order.unwrap_or_default(), + background: song.background.unwrap_or_default(), + background_type: song + .background_type + .unwrap_or_default(), + horizontal_text_alignment: song + .horizontal_text_alignment + .unwrap_or_default(), + vertical_text_alignment: song + .vertical_text_alignment + .unwrap_or_default(), + font: song.font.unwrap_or_default(), + font_size: song.font_size.unwrap_or_default(), + }; + + self.as_mut().add_song(song); + } + println!("--------------------------------------"); + println!("{:?}", self.as_mut().songs); + println!("--------------------------------------"); + } + + pub fn remove_item(mut self: Pin<&mut Self>, index: i32) -> bool { + if index < 0 || (index as usize) >= self.songs.len() { + return false; + } + let db = &mut self.as_mut().get_db(); + + let song_id = self.songs.get(index as usize).unwrap().id; + + let result = delete(songs.filter(id.eq(song_id))).execute(db); + + match result { + Ok(_i) => { + unsafe { + self.as_mut().begin_remove_rows( + &QModelIndex::default(), + index, + index, + ); + self.as_mut() + .rust_mut() + .songs + .remove(index as usize); + self.as_mut().end_remove_rows(); + } + println!("removed-item-at-index: {:?}", song_id); + println!("new-Vec: {:?}", self.as_mut().songs); + true + } + Err(_e) => { + println!("Cannot connect to database"); + false + } + } + } + + fn get_db(self: Pin<&mut Self>) -> SqliteConnection { + let mut data = dirs::data_local_dir().unwrap(); + data.push("lumina"); + data.push("library-db.sqlite3"); + let mut db_url = String::from("sqlite://"); + db_url.push_str(data.to_str().unwrap()); + println!("DB: {:?}", db_url); + + SqliteConnection::establish(&db_url).unwrap_or_else(|_| { + panic!("error connecting to {}", db_url) + }) + } + + pub fn new_song(mut self: Pin<&mut Self>) -> bool { + let song_id = self.rust().highest_id + 1; + let song_title = String::from("title"); + let db = &mut self.as_mut().get_db(); + + let song = Song { + id: song_id, + title: song_title.clone(), + ..Default::default() + }; + + let result = insert_into(songs) + .values(( + id.eq(&song_id), + title.eq(&song_title), + lyrics.eq(&song.lyrics), + author.eq(&song.author), + ccli.eq(&song.ccli), + audio.eq(&song.audio), + verse_order.eq(&song.verse_order), + background.eq(&song.background), + background_type.eq(&song.background_type), + horizontal_text_alignment + .eq(&song.horizontal_text_alignment), + vertical_text_alignment + .eq(&song.vertical_text_alignment), + font.eq(&song.font), + font_size.eq(&song.font_size), + )) + .execute(db); + println!("{:?}", result); + + match result { + Ok(_i) => { + self.as_mut().add_song(song); + println!("{:?}", self.as_mut().songs); + true + } + Err(_e) => { + println!("Cannot connect to database"); + false + } + } + } + + fn add_song(mut self: Pin<&mut Self>, song: self::Song) { + let index = self.as_ref().songs.len() as i32; + println!("{:?}", song); + + let count = self.as_ref().count; + self.as_mut().set_count(count + 1); + + unsafe { + self.as_mut().begin_insert_rows( + &QModelIndex::default(), + index, + index, + ); + self.as_mut().rust_mut().songs.push(song); + self.as_mut().end_insert_rows(); + } + } + + fn get_indices( + mut self: Pin<&mut Self>, + song_id: i32, + role: SongRoles, + ) -> (usize, QModelIndex, QVector_i32) { + let mut vector_roles = QVector_i32::default(); + vector_roles.append(self.as_ref().get_role(role)); + let index = self + .as_ref() + .songs + .iter() + .position(|x| x.id == song_id) + .unwrap(); + let model_index = self.as_ref().index( + index as i32, + 0, + &QModelIndex::default(), + ); + (index, model_index, vector_roles) + } + + pub fn update_title( + mut self: Pin<&mut Self>, + song_id: i32, + updated_title: QString, + ) -> bool { + let (index, model_index, vector_roles) = + self.as_mut().get_indices(song_id, SongRoles::Title); + let db = &mut self.as_mut().get_db(); + let result = update(songs.filter(id.eq(song_id))) + .set(title.eq(updated_title.to_string())) + .execute(db); + match result { + Ok(_i) => { + debug!(_i, index); + if let Some(song) = + self.as_mut().rust_mut().songs.get_mut(index) + { + debug!(?song); + song.title = updated_title.to_string(); + self.as_mut().data_changed( + &model_index, + &model_index, + &vector_roles, + ); + true + } else { + false + } + } + Err(_e) => false, + } + } + + pub fn update_lyrics( + mut self: Pin<&mut Self>, + song_id: i32, + updated_lyrics: QString, + ) -> bool { + let (index, model_index, vector_roles) = + self.as_mut().get_indices(song_id, SongRoles::Lyrics); + let db = &mut self.as_mut().get_db(); + let result = update(songs.filter(id.eq(song_id))) + .set(lyrics.eq(updated_lyrics.to_string())) + .execute(db); + match result { + Ok(_i) => { + if let Some(song) = + self.as_mut().rust_mut().songs.get_mut(index) + { + song.lyrics = updated_lyrics.to_string(); + self.as_mut().data_changed( + &model_index, + &model_index, + &vector_roles, + ); + true + } else { + false + } + } + Err(_e) => false, + } + } + + pub fn update_author( + mut self: Pin<&mut Self>, + song_id: i32, + updated_author: QString, + ) -> bool { + let (index, model_index, vector_roles) = + self.as_mut().get_indices(song_id, SongRoles::Author); + + let db = &mut self.as_mut().get_db(); + let result = update(songs.filter(id.eq(song_id))) + .set(author.eq(updated_author.to_string())) + .execute(db); + match result { + Ok(_i) => { + if let Some(song) = + self.as_mut().rust_mut().songs.get_mut(index) + { + song.author = updated_author.to_string(); + self.as_mut().data_changed( + &model_index, + &model_index, + &vector_roles, + ); + true + } else { + false + } + } + Err(_e) => false, + } + } + + pub fn update_audio( + mut self: Pin<&mut Self>, + song_id: i32, + updated_audio: QString, + ) -> bool { + let (index, model_index, vector_roles) = + self.as_mut().get_indices(song_id, SongRoles::Audio); + + let db = &mut self.as_mut().get_db(); + let result = update(songs.filter(id.eq(song_id))) + .set(audio.eq(updated_audio.to_string())) + .execute(db); + match result { + Ok(_i) => { + if let Some(song) = + self.as_mut().rust_mut().songs.get_mut(index) + { + song.audio = updated_audio.to_string(); + self.as_mut().data_changed( + &model_index, + &model_index, + &vector_roles, + ); + true + } else { + false + } + } + Err(_e) => false, + } + } + + pub fn update_ccli( + mut self: Pin<&mut Self>, + song_id: i32, + updated_ccli: QString, + ) -> bool { + let (index, model_index, vector_roles) = + self.as_mut().get_indices(song_id, SongRoles::Ccli); + + let db = &mut self.as_mut().get_db(); + let result = update(songs.filter(id.eq(song_id))) + .set(ccli.eq(updated_ccli.to_string())) + .execute(db); + match result { + Ok(_i) => { + if let Some(song) = + self.as_mut().rust_mut().songs.get_mut(index) + { + song.ccli = updated_ccli.to_string(); + self.as_mut().data_changed( + &model_index, + &model_index, + &vector_roles, + ); + true + } else { + false + } + } + Err(_e) => false, + } + } + + pub fn update_verse_order( + mut self: Pin<&mut Self>, + song_id: i32, + updated_verse_order: QString, + ) -> bool { + let (index, model_index, vector_roles) = + self.as_mut().get_indices(song_id, SongRoles::VerseOrder); + + let db = &mut self.as_mut().get_db(); + let result = update(songs.filter(id.eq(song_id))) + .set(verse_order.eq(updated_verse_order.to_string())) + .execute(db); + match result { + Ok(_i) => { + if let Some(song) = + self.as_mut().rust_mut().songs.get_mut(index) + { + song.verse_order = + updated_verse_order.to_string(); + self.as_mut().data_changed( + &model_index, + &model_index, + &vector_roles, + ); + true + } else { + false + } + } + Err(_e) => false, + } + } + + pub fn update_background( + mut self: Pin<&mut Self>, + song_id: i32, + updated_background: QString, + ) -> bool { + let (index, model_index, vector_roles) = + self.as_mut().get_indices(song_id, SongRoles::Background); + + let db = &mut self.as_mut().get_db(); + let result = update(songs.filter(id.eq(song_id))) + .set(background.eq(updated_background.to_string())) + .execute(db); + match result { + Ok(_i) => { + if let Some(song) = + self.as_mut().rust_mut().songs.get_mut(index) + { + song.background = updated_background.to_string(); + debug!( + background = ?updated_background, + model_index = ?model_index, + roles = vector_roles.get(0) + ); + self.as_mut().data_changed( + &model_index, + &model_index, + &vector_roles, + ); + self.as_mut().background_changed(); + true + } else { + false + } + } + Err(_e) => false, + } + } + + pub fn update_background_type( + mut self: Pin<&mut Self>, + song_id: i32, + updated_background_type: QString, + ) -> bool { + let (index, model_index, vector_roles) = self + .as_mut() + .get_indices(song_id, SongRoles::BackgroundType); + + let db = &mut self.as_mut().get_db(); + let result = update(songs.filter(id.eq(song_id))) + .set( + background_type + .eq(updated_background_type.to_string()), + ) + .execute(db); + match result { + Ok(_i) => { + if let Some(song) = + self.as_mut().rust_mut().songs.get_mut(index) + { + song.background_type = + updated_background_type.to_string(); + self.as_mut().data_changed( + &model_index, + &model_index, + &vector_roles, + ); + true + } else { + false + } + } + Err(_e) => false, + } + } + + pub fn update_horizontal_text_alignment( + mut self: Pin<&mut Self>, + song_id: i32, + updated_horizontal_text_alignment: QString, + ) -> bool { + let (index, model_index, vector_roles) = self + .as_mut() + .get_indices(song_id, SongRoles::HorizontalTextAlignment); + + let db = &mut self.as_mut().get_db(); + let result = + update(songs.filter(id.eq(song_id))) + .set(horizontal_text_alignment.eq( + updated_horizontal_text_alignment.to_string(), + )) + .execute(db); + match result { + Ok(_i) => { + if let Some(song) = + self.as_mut().rust_mut().songs.get_mut(index) + { + song.horizontal_text_alignment = + updated_horizontal_text_alignment.to_string(); + self.as_mut().data_changed( + &model_index, + &model_index, + &vector_roles, + ); + true + } else { + false + } + } + Err(_e) => false, + } + } + + pub fn update_vertical_text_alignment( + mut self: Pin<&mut Self>, + song_id: i32, + updated_vertical_text_alignment: QString, + ) -> bool { + let (index, model_index, vector_roles) = self + .as_mut() + .get_indices(song_id, SongRoles::VerticalTextAlignment); + + let db = &mut self.as_mut().get_db(); + let result = update(songs.filter(id.eq(song_id))) + .set( + vertical_text_alignment + .eq(updated_vertical_text_alignment.to_string()), + ) + .execute(db); + match result { + Ok(_i) => { + if let Some(song) = + self.as_mut().rust_mut().songs.get_mut(index) + { + song.vertical_text_alignment = + updated_vertical_text_alignment.to_string(); + self.as_mut().data_changed( + &model_index, + &model_index, + &vector_roles, + ); + true + } else { + false + } + } + Err(_e) => false, + } + } + + pub fn update_font( + mut self: Pin<&mut Self>, + song_id: i32, + updated_font: QString, + ) -> bool { + let (index, model_index, vector_roles) = + self.as_mut().get_indices(song_id, SongRoles::Font); + + let db = &mut self.as_mut().get_db(); + let result = update(songs.filter(id.eq(song_id))) + .set(font.eq(updated_font.to_string())) + .execute(db); + match result { + Ok(_i) => { + if let Some(song) = + self.as_mut().rust_mut().songs.get_mut(index) + { + song.font = updated_font.to_string(); + debug!(?updated_font); + self.as_mut().data_changed( + &model_index, + &model_index, + &vector_roles, + ); + true + } else { + false + } + } + Err(_e) => false, + } + } + + pub fn update_font_size( + mut self: Pin<&mut Self>, + song_id: i32, + updated_font_size: i32, + ) -> bool { + let (index, model_index, vector_roles) = + self.as_mut().get_indices(song_id, SongRoles::FontSize); + + let db = &mut self.as_mut().get_db(); + let result = update(songs.filter(id.eq(song_id))) + .set(font_size.eq(updated_font_size)) + .execute(db); + match result { + Ok(_i) => { + if let Some(song) = + self.as_mut().rust_mut().songs.get_mut(index) + { + song.font_size = updated_font_size; + self.as_mut().data_changed( + &model_index, + &model_index, + &vector_roles, + ); + true + } else { + false + } + } + Err(_e) => false, + } + } + + pub fn get_item( + self: Pin<&mut Self>, + index: i32, + ) -> QMap_QString_QVariant { + debug!(index); + let mut qvariantmap = QMap_QString_QVariant::default(); + let idx = self.index(index, 0, &QModelIndex::default()); + if !idx.is_valid() { + return qvariantmap; + } + let role_names = self.as_ref().role_names(); + let role_names_iter = role_names.iter(); + if let Some(song) = self.rust().songs.get(index as usize) { + debug!(?song); + for i in role_names_iter { + qvariantmap.insert( + QString::from(&i.1.to_string()), + self.as_ref().data(&idx, *i.0), + ); + } + }; + qvariantmap + } + + pub fn get_lyric_list( + mut self: Pin<&mut Self>, + index: i32, + ) -> QStringList { + println!("LYRIC_LIST: {index}"); + let mut lyric_list = QList_QString::default(); + let idx = self.index(index, 0, &QModelIndex::default()); + if !idx.is_valid() { + return QStringList::default(); + } + if let Some(song) = self.rust().songs.get(index as usize) { + if song.lyrics.is_empty() { + return QStringList::default(); + } + let raw_lyrics = song.lyrics.clone(); + println!("raw-lyrics: {:?}", raw_lyrics); + let vorder: Vec<&str> = + song.verse_order.split(' ').collect(); + let keywords = vec![ + "Verse 1", "Verse 2", "Verse 3", "Verse 4", + "Verse 5", "Verse 6", "Verse 7", "Verse 8", + "Chorus 1", "Chorus 2", "Chorus 3", "Chorus 4", + "Bridge 1", "Bridge 2", "Bridge 3", "Bridge 4", + "Intro 1", "Intro 2", "Ending 1", "Ending 2", + "Other 1", "Other 2", "Other 3", "Other 4", + ]; + let mut first_item = true; + + let mut lyric_map = HashMap::new(); + let mut verse_title = String::from(""); + let mut lyric = String::from(""); + for (i, line) in raw_lyrics.split("\n").enumerate() { + if keywords.contains(&line) { + if i != 0 { + println!("{verse_title}"); + println!("{lyric}"); + lyric_map.insert(verse_title, lyric); + lyric = String::from(""); + verse_title = line.to_string(); + // println!("{line}"); + // println!("\n"); + } else { + verse_title = line.to_string(); + // println!("{line}"); + // println!("\n"); + } + } else { + lyric.push_str(line); + lyric.push_str("\n"); + } + } + lyric_map.insert(verse_title, lyric); + println!("da-map: {:?}", lyric_map); + + for mut verse in vorder { + let mut verse_name = ""; + debug!(verse = verse); + for word in keywords.clone() { + let end_verse = + verse.get(1..2).unwrap_or_default(); + let beg_verse = + verse.get(0..1).unwrap_or_default(); + println!( + "verse: {:?}, beginning: {:?}, end: {:?}, word: {:?}", + verse, beg_verse, end_verse, word + ); + if word.starts_with(beg_verse) + && word.ends_with(end_verse) + { + verse_name = word; + println!("TITLE: {verse_name}"); + continue; + } + } + if let Some(lyric) = lyric_map.get(verse_name) { + if lyric.contains("\n\n") { + let split_lyrics: Vec<&str> = + lyric.split("\n\n").collect(); + for lyric in split_lyrics { + if lyric == "" { + continue; + } + lyric_list.append(QString::from(lyric)); + } + continue; + } + lyric_list.append(QString::from(lyric)); + } else { + println!("NOT WORKING!"); + }; + } + for lyric in lyric_list.iter() { + println!("da-list: {:?}", lyric); + } + } + QStringList::from(&lyric_list) + } + + fn get_role(&self, role: SongRoles) -> i32 { + match role { + SongRoles::Id => 0, + SongRoles::Title => 1, + SongRoles::Lyrics => 2, + SongRoles::Author => 3, + SongRoles::Ccli => 4, + SongRoles::Audio => 5, + SongRoles::VerseOrder => 6, + SongRoles::Background => 7, + SongRoles::BackgroundType => 8, + SongRoles::HorizontalTextAlignment => 9, + SongRoles::VerticalTextAlignment => 10, + SongRoles::Font => 11, + SongRoles::FontSize => 12, + _ => 0, } } } -// #[cfg(test)] -// mod tests { -// use super::*; -// use cxx_qt_lib::QStringList; // Replace 'some_module' with the actual module where QModelIndex is defined. +// QAbstractListModel implementation +impl song_model::SongModel { + fn data(&self, index: &QModelIndex, role: i32) -> QVariant { + let role = SongRoles { repr: role }; + if let Some(song) = self.songs.get(index.row() as usize) { + return match role { + SongRoles::Id => QVariant::from(&song.id), + SongRoles::Title => { + QVariant::from(&QString::from(&song.title)) + } + SongRoles::Lyrics => { + QVariant::from(&QString::from(&song.lyrics)) + } + SongRoles::Author => { + QVariant::from(&QString::from(&song.author)) + } + SongRoles::Ccli => { + QVariant::from(&QString::from(&song.ccli)) + } + SongRoles::Audio => { + QVariant::from(&QString::from(&song.audio)) + } + SongRoles::VerseOrder => { + QVariant::from(&QString::from(&song.verse_order)) + } + SongRoles::Background => { + QVariant::from(&QString::from(&song.background)) + } + SongRoles::BackgroundType => QVariant::from( + &QString::from(&song.background_type), + ), + SongRoles::HorizontalTextAlignment => QVariant::from( + &QString::from(&song.horizontal_text_alignment), + ), + SongRoles::VerticalTextAlignment => QVariant::from( + &QString::from(&song.vertical_text_alignment), + ), + SongRoles::Font => { + QVariant::from(&QString::from(&song.font)) + } + SongRoles::FontSize => { + QVariant::from(&song.font_size) + } + _ => QVariant::default(), + }; + } -// #[test] -// fn test_get_lyric_list() { -// // Create a test instance of your struct (you might need to adjust this based on your actual struct). -// let mut song_model = SongModel { -// highest_id: 0, -// songs: Vec::::new(), -// }; + QVariant::default() + } -// // this sets up the songmodel with the database -// // song_model.setup_wrapper(self); + // Example of overriding a C++ virtual method and calling the base class implementation. -// // Call the get_lyric_list function with specific inputs. -// let index = 0; // Replace with your desired test index. + // pub fn can_fetch_more(&self, parent: &QModelIndex) -> bool { + // self.base_can_fetch_more(parent) + // } -// let result = song_model.get_lyric_list(index); + pub fn role_names(&self) -> QHash_i32_QByteArray { + let mut roles = QHash_i32_QByteArray::default(); + roles.insert(SongRoles::Id.repr, QByteArray::from("id")); + roles + .insert(SongRoles::Title.repr, QByteArray::from("title")); + roles.insert( + SongRoles::Lyrics.repr, + QByteArray::from("lyrics"), + ); + roles.insert( + SongRoles::Author.repr, + QByteArray::from("author"), + ); + roles.insert(SongRoles::Ccli.repr, QByteArray::from("ccli")); + roles + .insert(SongRoles::Audio.repr, QByteArray::from("audio")); + roles.insert( + SongRoles::VerseOrder.repr, + QByteArray::from("vorder"), + ); + roles.insert( + SongRoles::Background.repr, + QByteArray::from("background"), + ); + roles.insert( + SongRoles::BackgroundType.repr, + QByteArray::from("backgroundType"), + ); + roles.insert( + SongRoles::HorizontalTextAlignment.repr, + QByteArray::from("horizontalTextAlignment"), + ); + roles.insert( + SongRoles::VerticalTextAlignment.repr, + QByteArray::from("verticalTextAlignment"), + ); + roles.insert(SongRoles::Font.repr, QByteArray::from("font")); + roles.insert( + SongRoles::FontSize.repr, + QByteArray::from("fontSize"), + ); + roles + } -// // Define your expected result here. For simplicity, let's assume an empty QStringList. -// let expected_result = QStringList::default(); - -// // Compare the actual result with the expected result using an assertion. -// assert_eq!(result, expected_result); -// } -// } + pub fn row_count(&self, _parent: &QModelIndex) -> i32 { + let cnt = self.rust().songs.len() as i32; + // println!("row count is {cnt}"); + cnt + } +} diff --git a/src/rust/utils.rs b/src/rust/utils.rs index 84d9a1c..a75c78e 100644 --- a/src/rust/utils.rs +++ b/src/rust/utils.rs @@ -1,4 +1,7 @@ +use std::pin::Pin; + use time::macros::format_description; +use tokio::runtime::Runtime; use tracing_subscriber::{ fmt::{self, time::LocalTime}, EnvFilter, @@ -47,30 +50,35 @@ mod db { #[cxx_qt::bridge] mod utilities { - use tokio::runtime::Runtime; + unsafe extern "RustQt" { + #[qobject] + #[qml_element] + type Utils = super::UtilsRust; - #[cxx_qt::qobject] - #[derive(Debug)] - pub struct Utils { - runtime: Runtime, - } - - impl Default for Utils { - fn default() -> Self { - Self { - runtime: tokio::runtime::Runtime::new().unwrap(), - } - } - } - - impl qobject::Utils { #[qinvokable] - pub fn setup(&self) { - crate::utils::setup(); + fn setup(self: Pin<&mut Utils>); + } +} + +#[derive(Debug)] +pub struct UtilsRust { + runtime: Runtime, +} + +impl Default for UtilsRust { + fn default() -> Self { + Self { + runtime: tokio::runtime::Runtime::new().unwrap(), } } } +impl utilities::Utils { + pub fn setup(mut self: Pin<&mut Self>) { + crate::utils::setup(); + } +} + pub fn setup() { tracing_subscriber::FmtSubscriber::builder() .pretty() diff --git a/src/rust/video_model.rs b/src/rust/video_model.rs index 2c92b1e..ca203ea 100644 --- a/src/rust/video_model.rs +++ b/src/rust/video_model.rs @@ -25,7 +25,7 @@ mod video_model { } #[qenum(VideoModel)] - enum Role { + enum VideoRoles { Id, Title, Path, @@ -38,7 +38,7 @@ mod video_model { #[qobject] #[base = "QAbstractListModel"] #[qml_element] - #[qproperty(i32, count_rows)] + #[qproperty(i32, count)] type VideoModel = super::VideoModelRust; #[inherit] @@ -88,13 +88,13 @@ mod video_model { fn update_start_time( self: Pin<&mut VideoModel>, index: i32, - updated_start_time: QString, + updated_start_time: f32, ) -> bool; #[qinvokable] fn update_end_time( self: Pin<&mut VideoModel>, index: i32, - updated_end_time: QString, + updated_end_time: f32, ) -> bool; } @@ -173,17 +173,22 @@ mod video_model { fn row_count(self: &VideoModel, _parent: &QModelIndex) -> i32; - #[qinvokable] - fn count(self: &VideoModel) -> i32; } } use crate::models::*; use crate::schema::videos::dsl::*; -use crate::video_model::video_model::Video; +use cxx_qt::CxxQtType; +use cxx_qt_lib::{QByteArray, QModelIndex, QString, QUrl, QVariant}; use diesel::sqlite::SqliteConnection; use diesel::{delete, insert_into, prelude::*, update}; use std::path::{Path, PathBuf}; +use std::pin::Pin; + +use self::video_model::{ + QHash_i32_QByteArray, QMap_QString_QVariant, QVector_i32, + VideoRoles, +}; #[derive(Default, Clone, Debug)] pub struct Video { @@ -197,15 +202,16 @@ pub struct Video { #[derive(Default, Debug)] pub struct VideoModelRust { + count: i32, highest_id: i32, videos: Vec, } -impl qobject::VideoModel { +impl video_model::VideoModel { pub fn clear(mut self: Pin<&mut Self>) { unsafe { self.as_mut().begin_reset_model(); - self.as_mut().videos_mut().clear(); + self.as_mut().rust_mut().videos.clear(); self.as_mut().end_reset_model(); } } @@ -215,7 +221,7 @@ impl qobject::VideoModel { let results = videos .load::(db) .expect("Error loading videos"); - self.as_mut().set_highest_id(0); + self.as_mut().rust_mut().highest_id = 0; println!("SHOWING VIDEOS"); println!("--------------"); @@ -224,8 +230,8 @@ impl qobject::VideoModel { println!("{}", video.id); println!("{}", video.path); println!("--------------"); - if self.as_mut().highest_id() < &video.id { - self.as_mut().set_highest_id(video.id); + if self.as_mut().highest_id < video.id { + self.as_mut().rust_mut().highest_id = video.id; } let img = self::Video { @@ -240,17 +246,17 @@ impl qobject::VideoModel { self.as_mut().add_video(img); } println!("--------------------------------------"); - println!("{:?}", self.as_mut().videos()); + println!("{:?}", self.as_mut().videos); println!("--------------------------------------"); } pub fn remove_item(mut self: Pin<&mut Self>, index: i32) -> bool { - if index < 0 || (index as usize) >= self.videos().len() { + if index < 0 || (index as usize) >= self.videos.len() { return false; } let db = &mut self.as_mut().get_db(); - let video_id = self.videos().get(index as usize).unwrap().id; + let video_id = self.videos.get(index as usize).unwrap().id; let result = delete(videos.filter(id.eq(video_id))).execute(db); @@ -263,11 +269,14 @@ impl qobject::VideoModel { index, index, ); - self.as_mut().videos_mut().remove(index as usize); + self.as_mut() + .rust_mut() + .videos + .remove(index as usize); self.as_mut().end_remove_rows(); } println!("removed-item-at-index: {:?}", video_id); - println!("new-Vec: {:?}", self.as_mut().videos()); + println!("new-Vec: {:?}", self.as_mut().videos); true } Err(_e) => { @@ -300,7 +309,7 @@ impl qobject::VideoModel { if self.as_mut().add_item(video_id, video_title, video_path) { println!("filename: {:?}", name); - self.as_mut().set_highest_id(video_id); + self.as_mut().rust_mut().highest_id = video_id; } else { println!("Error in inserting item"); } @@ -339,7 +348,7 @@ impl qobject::VideoModel { match result { Ok(_i) => { self.as_mut().add_video(video); - println!("{:?}", self.as_mut().videos()); + println!("{:?}", self.as_mut().videos); true } Err(_e) => { @@ -352,15 +361,17 @@ impl qobject::VideoModel { } fn add_video(mut self: Pin<&mut Self>, video: self::Video) { - let index = self.as_ref().videos().len() as i32; + let index = self.as_ref().videos.len() as i32; println!("{:?}", video); + let count = self.as_mut().count; + self.as_mut().set_count(count + 1); unsafe { self.as_mut().begin_insert_rows( &QModelIndex::default(), index, index, ); - self.as_mut().videos_mut().push(video); + self.as_mut().rust_mut().videos.push(video); self.as_mut().end_insert_rows(); } } @@ -389,14 +400,14 @@ impl qobject::VideoModel { qvariantmap } - fn get_role(&self, role: Role) -> i32 { + fn get_role(&self, role: VideoRoles) -> i32 { match role { - Role::IdRole => 0, - Role::TitleRole => 1, - Role::PathRole => 2, - Role::StartTimeRole => 3, - Role::EndTimeRole => 4, - Role::LoopingRole => 5, + VideoRoles::Id => 0, + VideoRoles::Title => 1, + VideoRoles::Path => 2, + VideoRoles::StartTime => 3, + VideoRoles::EndTime => 4, + VideoRoles::Looping => 5, _ => 0, } } @@ -408,7 +419,7 @@ impl qobject::VideoModel { ) -> bool { let mut vector_roles = QVector_i32::default(); vector_roles - .append(self.as_ref().get_role(Role::LoopingRole)); + .append(self.as_ref().get_role(VideoRoles::Looping)); let model_index = &self.as_ref().index(index, 0, &QModelIndex::default()); println!("rust-video: {:?}", index); @@ -422,14 +433,15 @@ impl qobject::VideoModel { Ok(_i) => { for video in self .as_mut() - .videos_mut() + .rust_mut() + .videos .iter_mut() .filter(|x| x.id == index) { video.looping = loop_value.clone(); println!("rust-video: {:?}", video.title); } - self.as_mut().emit_data_changed( + self.as_mut().data_changed( model_index, model_index, &vector_roles, @@ -448,7 +460,7 @@ impl qobject::VideoModel { ) -> bool { let mut vector_roles = QVector_i32::default(); vector_roles - .append(self.as_ref().get_role(Role::EndTimeRole)); + .append(self.as_ref().get_role(VideoRoles::EndTime)); let model_index = &self.as_ref().index(index, 0, &QModelIndex::default()); @@ -460,13 +472,14 @@ impl qobject::VideoModel { Ok(_i) => { for video in self .as_mut() - .videos_mut() + .rust_mut() + .videos .iter_mut() .filter(|x| x.id == index) { video.end_time = updated_end_time.clone(); } - self.as_mut().emit_data_changed( + self.as_mut().data_changed( model_index, model_index, &vector_roles, @@ -485,7 +498,7 @@ impl qobject::VideoModel { ) -> bool { let mut vector_roles = QVector_i32::default(); vector_roles - .append(self.as_ref().get_role(Role::StartTimeRole)); + .append(self.as_ref().get_role(VideoRoles::StartTime)); let model_index = &self.as_ref().index(index, 0, &QModelIndex::default()); @@ -497,13 +510,14 @@ impl qobject::VideoModel { Ok(_i) => { for video in self .as_mut() - .videos_mut() + .rust_mut() + .videos .iter_mut() .filter(|x| x.id == index) { video.start_time = updated_start_time.clone(); } - self.as_mut().emit_data_changed( + self.as_mut().data_changed( model_index, model_index, &vector_roles, @@ -521,7 +535,8 @@ impl qobject::VideoModel { updated_title: QString, ) -> bool { let mut vector_roles = QVector_i32::default(); - vector_roles.append(self.as_ref().get_role(Role::TitleRole)); + vector_roles + .append(self.as_ref().get_role(VideoRoles::Title)); let model_index = &self.as_ref().index(index, 0, &QModelIndex::default()); @@ -533,7 +548,8 @@ impl qobject::VideoModel { Ok(_i) => { for video in self .as_mut() - .videos_mut() + .rust_mut() + .videos .iter_mut() .filter(|x| x.id == index) { @@ -541,12 +557,11 @@ impl qobject::VideoModel { println!("rust-title: {:?}", video.title); } // TODO this seems to not be updating in the actual list - self.as_mut().emit_data_changed( + self.as_mut().data_changed( model_index, model_index, &vector_roles, ); - // self.as_mut().emit_title_changed(); println!("rust-title: {:?}", updated_title); true } @@ -560,7 +575,7 @@ impl qobject::VideoModel { updated_path: QString, ) -> bool { let mut vector_roles = QVector_i32::default(); - vector_roles.append(self.as_ref().get_role(Role::PathRole)); + vector_roles.append(self.as_ref().get_role(VideoRoles::Path)); let model_index = &self.as_ref().index(index, 0, &QModelIndex::default()); @@ -572,14 +587,15 @@ impl qobject::VideoModel { Ok(_i) => { for video in self .as_mut() - .videos_mut() + .rust_mut() + .videos .iter_mut() .filter(|x| x.id == index) { video.path = updated_path.clone(); println!("rust-title: {:?}", video.title); } - self.as_mut().emit_data_changed( + self.as_mut().data_changed( model_index, model_index, &vector_roles, @@ -593,23 +609,21 @@ impl qobject::VideoModel { } // QAbstractListModel implementation -impl qobject::VideoModel { +impl video_model::VideoModel { fn data(&self, index: &QModelIndex, role: i32) -> QVariant { - let role = qobject::Roles { repr: role }; - if let Some(video) = self.videos().get(index.row() as usize) { + let role = VideoRoles { repr: role }; + if let Some(video) = self.videos.get(index.row() as usize) { return match role { - qobject::Role::Id => QVariant::from(&video.id), - qobject::Role::Title => QVariant::from(&video.title), - qobject::Role::Path => QVariant::from(&video.path), - qobject::Role::StartTime => { + VideoRoles::Id => QVariant::from(&video.id), + VideoRoles::Title => QVariant::from(&video.title), + VideoRoles::Path => QVariant::from(&video.path), + VideoRoles::StartTime => { QVariant::from(&video.start_time) } - qobject::Role::EndTime => { + VideoRoles::EndTime => { QVariant::from(&video.end_time) } - qobject::Role::Looping => { - QVariant::from(&video.looping) - } + VideoRoles::Looping => QVariant::from(&video.looping), _ => QVariant::default(), }; } @@ -619,35 +633,32 @@ impl qobject::VideoModel { // Example of overriding a C++ virtual method and calling the base class implementation. - pub fn can_fetch_more(&self, parent: &QModelIndex) -> bool { - self.base_can_fetch_more(parent) - } + // pub fn can_fetch_more(&self, parent: &QModelIndex) -> bool { + // self.base_can_fetch_more(parent) + // } pub fn role_names(&self) -> QHash_i32_QByteArray { let mut roles = QHash_i32_QByteArray::default(); + roles.insert(VideoRoles::Id.repr, QByteArray::from("id")); roles.insert( - qobject::Roles::Id.repr, - cxx_qt_lib::QByteArray::from("id"), + VideoRoles::Title.repr, + QByteArray::from("title"), ); roles.insert( - qobject::Roles::Title.repr, - cxx_qt_lib::QByteArray::from("title"), + VideoRoles::Path.repr, + QByteArray::from("filePath"), ); roles.insert( - qobject::Roles::Path.repr, - cxx_qt_lib::QByteArray::from("filePath"), + VideoRoles::StartTime.repr, + QByteArray::from("startTime"), ); roles.insert( - qobject::Roles::StartTime.repr, - cxx_qt_lib::QByteArray::from("startTime"), + VideoRoles::EndTime.repr, + QByteArray::from("endTime"), ); roles.insert( - qobject::Roles::EndTime.repr, - cxx_qt_lib::QByteArray::from("endTime"), - ); - roles.insert( - qobject::Roles::Looping.repr, - cxx_qt_lib::QByteArray::from("loop"), + VideoRoles::Looping.repr, + QByteArray::from("loop"), ); roles } @@ -657,8 +668,4 @@ impl qobject::VideoModel { // println!("row count is {cnt}"); cnt } - - pub fn count(&self) -> i32 { - self.rust().videos.len() as i32 - } } diff --git a/src/rust/ytdl.rs b/src/rust/ytdl.rs index f284729..7ee7c91 100644 --- a/src/rust/ytdl.rs +++ b/src/rust/ytdl.rs @@ -1,9 +1,5 @@ #[cxx_qt::bridge] mod ytdl { - use dirs; - use std::{fs, thread}; - use youtube_dl::YoutubeDl; - unsafe extern "C++" { include!("cxx-qt-lib/qurl.h"); type QUrl = cxx_qt_lib::QUrl; @@ -11,91 +7,106 @@ mod ytdl { type QString = cxx_qt_lib::QString; } - #[derive(Clone, Default)] - #[cxx_qt::qobject] - pub struct Ytdl { - #[qproperty] - title: QString, - #[qproperty] - thumbnail: QUrl, - #[qproperty] - loaded: bool, - #[qproperty] - loading: bool, - #[qproperty] - file: QUrl, + unsafe extern "RustQt" { + #[qobject] + #[qml_element] + #[qproperty(QString, title)] + #[qproperty(QUrl, thumbnail)] + #[qproperty(bool, loaded)] + #[qproperty(bool, loading)] + #[qproperty(QUrl, file)] + type Ytdl = super::YtdlRust; + + #[qinvokable] + fn get_video(self: Pin<&mut Ytdl>, url: QUrl) -> bool; } - impl qobject::Ytdl { - #[qinvokable] - pub fn get_video( - mut self: Pin<&mut Self>, - url: QUrl, - ) -> bool { - if !url.is_valid() { - false - } else { - let data_dir = dirs::data_local_dir().unwrap(); - if let Some(mut data_dir) = dirs::data_local_dir() { - data_dir.push("librepresenter"); - data_dir.push("ytdl"); - if !data_dir.exists() { - fs::create_dir(&data_dir) - .expect("Could not create ytdl dir"); - } - println!("{:?}", data_dir); - self.as_mut().set_loading(true); - let thread = self.qt_thread(); - let runtime = - tokio::runtime::Runtime::new().unwrap(); - runtime.spawn(async move { - let url = url.to_string(); - let output_dirs = data_dir.to_str().unwrap(); - println!("{output_dirs}"); - let ytdl = YoutubeDl::new(url) - .socket_timeout("15") - .output_directory(output_dirs) - .output_template("%(title)s.%(ext)s") - .download(true) - .run() - .unwrap(); - let output = - ytdl.into_single_video().unwrap(); - println!("{:?}", output.title); - println!("{:?}", output.thumbnail); - println!("{:?}", output.url); - let title = QString::from(&output.title); - let thumbnail = QUrl::from( - &output.thumbnail.unwrap_or_default(), - ); - let mut file = String::from(output_dirs); - file.push_str("/"); - file.push_str(&output.title); - file.push_str("."); - file.push_str( - &output.ext.unwrap_or_default(), - ); - println!("{:?}", file); + impl cxx_qt::Threading for Ytdl {} +} - thread.queue(move |mut qobject_ytdl| { - qobject_ytdl.as_mut().set_loaded(true); - qobject_ytdl.as_mut().set_loading(false); - qobject_ytdl.as_mut().set_title(title); - qobject_ytdl - .as_mut() - .set_thumbnail(thumbnail); - qobject_ytdl - .as_mut() - .set_file(QUrl::from(&file)); - }) - }); - true - } else { - false +use cxx_qt::{CxxQtType, Threading}; +use cxx_qt_lib::{QString, QUrl}; +use dirs; +use std::{fs, thread, pin::Pin}; +use youtube_dl::YoutubeDl; + +#[derive(Clone, Default)] +pub struct YtdlRust { + title: QString, + thumbnail: QUrl, + loaded: bool, + loading: bool, + file: QUrl, +} + +impl ytdl::Ytdl { + pub fn get_video( + mut self: Pin<&mut Self>, + url: QUrl, + ) -> bool { + if !url.is_valid() { + false + } else { + let data_dir = dirs::data_local_dir().unwrap(); + if let Some(mut data_dir) = dirs::data_local_dir() { + data_dir.push("librepresenter"); + data_dir.push("ytdl"); + if !data_dir.exists() { + fs::create_dir(&data_dir) + .expect("Could not create ytdl dir"); } + println!("{:?}", data_dir); + self.as_mut().set_loading(true); + let thread = self.qt_thread(); + let runtime = + tokio::runtime::Runtime::new().unwrap(); + runtime.spawn(async move { + let url = url.to_string(); + let output_dirs = data_dir.to_str().unwrap(); + println!("{output_dirs}"); + let ytdl = YoutubeDl::new(url) + .socket_timeout("15") + .output_directory(output_dirs) + .output_template("%(title)s.%(ext)s") + .download(true) + .run() + .unwrap(); + let output = + ytdl.into_single_video().unwrap(); + println!("{:?}", output.title); + println!("{:?}", output.thumbnail); + println!("{:?}", output.url); + let title = QString::from(&output.title); + let thumbnail = QUrl::from( + &output.thumbnail.unwrap_or_default(), + ); + let mut file = String::from(output_dirs); + file.push_str("/"); + file.push_str(&output.title); + file.push_str("."); + file.push_str( + &output.ext.unwrap_or_default(), + ); + println!("{:?}", file); + + thread.queue(move |mut qobject_ytdl| { + qobject_ytdl.as_mut().set_loaded(true); + qobject_ytdl.as_mut().set_loading(false); + qobject_ytdl.as_mut().set_title(title); + qobject_ytdl + .as_mut() + .set_thumbnail(thumbnail); + qobject_ytdl + .as_mut() + .set_file(QUrl::from(&file)); + }) + }); + true + } else { + false } } - - async fn dl_video() {} } + + async fn dl_video() {} }