diff --git a/.gitignore b/.gitignore index 771d7a4..217cbd8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,7 @@ +.cache +.qmake.stash +./src + # C++ objects and libs *.slo *.lo @@ -9,6 +13,10 @@ *.so.* *.dll *.dylib +Build +checks.json +.vscode +build # Qt-es object_script.*.Release @@ -16,6 +24,7 @@ object_script.*.Debug *_plugin_import.cpp /.qmake.cache /.qmake.stash +src/*.qmake.stash *.pro.user *.pro.user.* *.qbs.user diff --git a/CMakeLists.txt b/CMakeLists.txt deleted file mode 100644 index e087f6b..0000000 --- a/CMakeLists.txt +++ /dev/null @@ -1,43 +0,0 @@ -cmake_minimum_required(VERSION 3.16) - -project(MediaLibraryBuild VERSION 1.0 LANGUAGES CXX) - -# Qt5: automatizza moc, uic, rcc -set(CMAKE_AUTOMOC ON) -set(CMAKE_AUTORCC ON) -set(CMAKE_AUTOUIC ON) - -set(CMAKE_CXX_STANDARD 17) -set(CMAKE_CXX_STANDARD_REQUIRED ON) - -# Raccoglie tutti i file .cpp e .h nella cartella src/ -file(GLOB_RECURSE SOURCES CONFIGURE_DEPENDS src/*.cpp src/*.h) - -# Crea l'eseguibile principale -add_executable(${PROJECT_NAME} ${SOURCES}) - -target_include_directories(${PROJECT_NAME} PRIVATE src) - -# Trova e linka le librerie Qt necessarie -find_package(Qt5 REQUIRED COMPONENTS Core Widgets Gui) - -target_link_libraries(${PROJECT_NAME} PRIVATE Qt5::Core Qt5::Widgets Qt5::Gui) - -# Imposta la cartella output dell'eseguibile -set_target_properties(${PROJECT_NAME} PROPERTIES - RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR} -) - -# Abilita il supporto ai test -enable_testing() - -# Test (facoltativi) -file(GLOB_RECURSE TEST_SOURCES CONFIGURE_DEPENDS src/test*.cpp) - -foreach(test_src ${TEST_SOURCES}) - get_filename_component(test_name ${test_src} NAME_WE) - add_executable(${test_name} ${test_src}) - target_include_directories(${test_name} PRIVATE src) - target_link_libraries(${test_name} PRIVATE Qt5::Core Qt5::Widgets Qt5::Gui) - add_test(NAME ${test_name} COMMAND ${test_name}) -endforeach() diff --git a/src/Media/Album.cpp b/src/Media/Album.cpp index d20ecf3..ef163d7 100644 --- a/src/Media/Album.cpp +++ b/src/Media/Album.cpp @@ -16,4 +16,67 @@ const std::vector &Album::getBandMembers() const { return band_members_; } const std::vector &Album::getSongs() const { return songs_; } +bool Album::operator==(const Media &other) const { + const Album *other_album = dynamic_cast(&other); + if (other_album) { + return Media::operator==(*other_album) && band_ == other_album->band_ && + band_members_ == other_album->band_members_ && + songs_ == other_album->songs_; + } + return false; +} + +std::unique_ptr Album::clone() const { + return std::make_unique(*this); +} + + +bool Album::filter(const Media& album) const { + // Riutilizzo filtro base di Media + if (!Media::filter(album)) + return false; + + // Cast to Album to access Album-specific members + const Album* albumPtr = dynamic_cast(&album); + if (!albumPtr) + return false; + + // Band + if (!band_.empty() && !stringContainsIgnoreCase(albumPtr->getBand(), band_)) + return false; + + // Band members (ogni membro richiesto deve matchare almeno uno esistente) + if (!band_members_.empty()) { + for (const auto& memberFilter : band_members_) { + bool found = false; + for (const auto& m : albumPtr->getBandMembers()) { + if (stringContainsIgnoreCase(m, memberFilter)) { + found = true; + break; + } + } + if (!found) { + return false; + } + } + } + + // Songs (ogni canzone richiesta deve matchare almeno una esistente) + if (!songs_.empty()) { + for (const auto& songFilter : songs_) { + bool found = false; + for (const auto& s : albumPtr->getSongs()) { + if (stringContainsIgnoreCase(s, songFilter)) { + found = true; + break; + } + } + if (!found) { + return false; + } + } + } + return true; +} + } // namespace media diff --git a/src/Media/Album.h b/src/Media/Album.h index 99c802e..6efe82a 100644 --- a/src/Media/Album.h +++ b/src/Media/Album.h @@ -13,11 +13,18 @@ class Album : public Media { Album(const std::string &title, int release, const std::string &language, bool favourite, const std::vector &genres, const std::string &img_path, const std::string ¬es, - const std::string &band, const std::vector &band_members, - const std::vector &songs); + const std::string &band = "", const std::vector &band_members = {}, + const std::vector &songs = {}); const std::string &getBand() const; const std::vector &getBandMembers() const; const std::vector &getSongs() const; + bool operator==(const Media &other) const override; + + std::unique_ptr clone() const override; + + bool filter(const Media& album) const override; + }; } // namespace media + #endif diff --git a/src/Media/AudioBook.cpp b/src/Media/AudioBook.cpp index b1aa6af..f9d91f8 100644 --- a/src/Media/AudioBook.cpp +++ b/src/Media/AudioBook.cpp @@ -12,8 +12,17 @@ AudioBook::AudioBook(const std::string& title, int publicationYear, const std::s narrator_(narrator), streamingService_(streamingService) {} -void AudioBook::accept(IConstMediaVisitor& v) const { - v.visit(*this); +bool AudioBook::operator==(const Media& other) const { + const AudioBook* otherAudioBook = dynamic_cast(&other); + if (otherAudioBook) { + return Novel::operator==(*otherAudioBook) && narrator_ == otherAudioBook->narrator_ && + streamingService_ == otherAudioBook->streamingService_; + } + return false; +} + +std::unique_ptr AudioBook::clone() const { + return std::make_unique(*this); } std::string AudioBook::getNarrator() const { @@ -32,4 +41,21 @@ void AudioBook::setStreamingService(const std::string& service) { streamingService_ = service; } +bool AudioBook::filter(const Media& input) const { + if (!Novel::filter(input)) + return false; + const AudioBook* audiobookPtr = dynamic_cast(&input); + if (!audiobookPtr) + return false; // Protegge da cast fallito + + // Filtro specifico AudioBook + if (!narrator_.empty() && !stringContainsIgnoreCase(audiobookPtr->getNarrator(), narrator_)) + return false; + + if (!streamingService_.empty() && !stringContainsIgnoreCase(audiobookPtr->getStreamingService(), streamingService_)) + return false; + + return true; +} + } \ No newline at end of file diff --git a/src/Media/AudioBook.h b/src/Media/AudioBook.h index ecb7c60..2012e99 100644 --- a/src/Media/AudioBook.h +++ b/src/Media/AudioBook.h @@ -1,5 +1,5 @@ -#ifndef AudioBook_H -#define AudioBook_H +#ifndef MEDIA_AUDIOBOOK_H +#define MEDIA_AUDIOBOOK_H #include "Novel.h" @@ -11,21 +11,26 @@ class AudioBook : public Novel { std::string streamingService_; public: + //durata è in minuti e usa il campo dati pagine di Novel AudioBook(const std::string& title, int publicationYear, const std::string& language, bool favorite, const std::vector& genres, const std::string& imagePath, const std::string& notes, const std::string& author, const std::string& publisher, unsigned int duration, const std::string& series, const std::string& isbn, - const std::string& narrator, const std::string& streamingService); + const std::string& narrator = "", const std::string& streamingService = ""); - void accept(IConstMediaVisitor& v) const override; + bool operator==(const Media& other) const override; std::string getNarrator() const; std::string getStreamingService() const; void setNarrator(const std::string& narrator); void setStreamingService(const std::string& service); + + std::unique_ptr clone() const override; + + bool filter(const Media& audiobook) const override; }; } -#endif // AudioBook_H \ No newline at end of file +#endif // MEDIA_AUDIOBOOK_H \ No newline at end of file diff --git a/src/Media/Ebook.cpp b/src/Media/Ebook.cpp index 9a26700..cb4d562 100644 --- a/src/Media/Ebook.cpp +++ b/src/Media/Ebook.cpp @@ -11,9 +11,14 @@ Ebook::Ebook(const std::string& title, int publicationYear, const std::string& l author, publisher, pages, series, isbn), fileSizeBytes_(fileSizeBytes), drm_(drm) {} -void Ebook::accept(IConstMediaVisitor& v) const { - v.visit(*this); -} +bool Ebook::operator==(const Media& other) const { + const Ebook* otherEbook = dynamic_cast(&other); + if (otherEbook) { + return Novel::operator==(*otherEbook) && fileSizeBytes_ == otherEbook->fileSizeBytes_ && + drm_ == otherEbook->drm_; + } + return false; +} unsigned int Ebook::getFileSizeBytes() const { return fileSizeBytes_; @@ -31,4 +36,28 @@ void Ebook::setDrm(bool drm) { drm_ = drm; } +std::unique_ptr Ebook::clone() const { + return std::make_unique(*this); +} + +bool Ebook::filter(const Media& input) const { + // Riutilizzo filtro base di Novel + if (!Novel::filter(input)) + return false; + // Cast to Ebook to access Ebook-specific members + const Ebook* ebookPtr = dynamic_cast(&input); + if (!ebookPtr) + return false; + + // File size filter + if (fileSizeBytes_ > 0 && ebookPtr->getFileSizeBytes() != fileSizeBytes_) + return false; + + // DRM filter + if (drm_ && ebookPtr->hasDrm() != drm_) + return false; + + return true; +} + } \ No newline at end of file diff --git a/src/Media/Ebook.h b/src/Media/Ebook.h index 367f85b..e277746 100644 --- a/src/Media/Ebook.h +++ b/src/Media/Ebook.h @@ -1,5 +1,5 @@ -#ifndef EBOOK_H -#define EBOOK_H +#ifndef MEDIA_EBOOK_H +#define MEDIA_EBOOK_H #include "Novel.h" @@ -15,17 +15,22 @@ class Ebook : public Novel { bool favorite, const std::vector& genres, const std::string& imagePath, const std::string& notes, const std::string& author, const std::string& publisher, unsigned int pages, const std::string& series, const std::string& isbn, - unsigned int fileSizeBytes, bool drm); + unsigned int fileSizeBytes = 0, bool drm = false); - void accept(IConstMediaVisitor& v) const override; + bool operator==(const Media& other) const override; unsigned int getFileSizeBytes() const; bool hasDrm() const; void setFileSizeBytes(unsigned int size); void setDrm(bool drm); + + std::unique_ptr clone() const override; + + bool filter(const Media& ebook) const override; + }; } -#endif // EBOOK_H \ No newline at end of file +#endif // MEDIA_EBOOK_H \ No newline at end of file diff --git a/src/Media/IMedia.h b/src/Media/IMedia.h index 4f603b7..677381b 100644 --- a/src/Media/IMedia.h +++ b/src/Media/IMedia.h @@ -1,18 +1,16 @@ -#ifndef IMedia_H -#define IMedia_H +#ifndef MEDIA_IMedia_H +#define MEDIA_IMedia_H #include "IConstMediaVisitor.h" - namespace media { - class IMedia { virtual void accept(IConstMediaVisitor &) const = 0; virtual bool open() = 0; + virtual std::unique_ptr clone() const = 0; }; } - #endif \ No newline at end of file diff --git a/src/Media/Media.cpp b/src/Media/Media.cpp index fbad213..3e7b8dc 100644 --- a/src/Media/Media.cpp +++ b/src/Media/Media.cpp @@ -1,4 +1,8 @@ #include "Media.h" +#include +#include +#include +#include namespace media { Media::Media(const std::string &title, int release, const std::string &language, @@ -14,12 +18,63 @@ Media::Media(const std::string &title, int release, const std::string &language, void Media::accept(IConstMediaVisitor &v) const {} +std::unique_ptr media::Media::clone() const { + return std::make_unique(*this); +} + + +bool Media::operator==(const Media &other) const { + return title_ == other.title_ && release_ == other.release_ && + language_ == other.language_ && favourite_ == other.favourite_ && + genres_ == other.genres_ && img_path_ == other.img_path_ && + notes_ == other.notes_; +} + bool Media::open() { notes_ = ""; std::cout<< "Media::open()" << std::endl; return false; } +bool Media::filter(const Media& media) const { + // Title (substring, case-insensitive) + if (!getTitle().empty() && !stringContainsIgnoreCase(media.getTitle(), getTitle())) + return false; + + // Release (confronto stretto) + if (getRelease() != std::numeric_limits::min() && + media.getRelease() != getRelease()) + return false; + + // Language (substring, case-insensitive) + if (!getLanguage().empty() && media.getLanguage() != getLanguage()) + return false; + + // Favourite (confronto booleano) + if (isFavourite() && media.isFavourite() != isFavourite()) + return false; + + // Generi (match parziale case-insensitive su ogni genere richiesto) + if (!getGenres().empty()) { + const auto& mediaGenres = media.getGenres(); + for (const auto& genreFilter : getGenres()) { + bool found = false; + for (const auto& g : mediaGenres) { + if (stringContainsIgnoreCase(g, genreFilter)) { + found = true; + break; + } + } + if (!found) { + return false; + } + } + } + + return true; +} + + const std::string &Media::getTitle() const { return title_; } int Media::getRelease() const { return release_; } const std::string &Media::getLanguage() const { return language_; }; diff --git a/src/Media/Media.h b/src/Media/Media.h index 2eb83c4..7d607c4 100644 --- a/src/Media/Media.h +++ b/src/Media/Media.h @@ -3,9 +3,12 @@ #include #include #include +#include +#include #include "IMedia.h" #include "IConstMediaVisitor.h" +#include "StringUtils.h" namespace media { class Media : IMedia{ @@ -18,13 +21,15 @@ class Media : IMedia{ std::string img_path_; std::string notes_; - protected: - Media(const std::string &title, int release, const std::string &language, - bool favourite, const std::vector &genres, - const std::string &img_path, const std::string ¬es); - - public: + + public: + + Media(const std::string &title = "", int release = std::numeric_limits::max(), const std::string &language = "", + bool favourite = false, const std::vector &genres = {}, + const std::string &img_path = "", const std::string ¬es = ""); + virtual bool operator==(const Media &other) const; + void accept(IConstMediaVisitor &) const override; bool open() override; @@ -38,6 +43,11 @@ class Media : IMedia{ const std::vector &getGenres() const; const std::string &getImgPath() const; const std::string &getNotes() const; -}; + + virtual std::unique_ptr clone() const; + + + virtual bool filter(const Media &media) const; +}; } // namespace media #endif diff --git a/src/Media/Movie.cpp b/src/Media/Movie.cpp index 1e7a3a1..59652ab 100644 --- a/src/Media/Movie.cpp +++ b/src/Media/Movie.cpp @@ -10,7 +10,61 @@ Movie::Movie(const std::string &title, int release, const std::string &language, cast_(cast), length_(length), universe_(universe) {} +bool Movie::operator==(const Media &other) const { + const Movie *otherMovie = dynamic_cast(&other); + if (otherMovie) { + return Media::operator==(*otherMovie) && cast_ == otherMovie->cast_ && + length_ == otherMovie->length_ && universe_ == otherMovie->universe_; + } + return false; +} + +std::unique_ptr Movie::clone() const { + return std::make_unique(*this); +} + const std::vector &Movie::getCast() const { return cast_; } unsigned int Movie::getLength() const { return length_; } const std::string &Movie::getUniverse() const { return universe_; } + +bool Movie::filter(const Media& movie) const { + + if (!Media::filter(movie)) + return false; + + // Cast (match parziale, case-insensitive) + const Movie* moviePtr = dynamic_cast(&movie); + if (!moviePtr) { + return false; + } + if (!cast_.empty()) { + const auto& movieCast = moviePtr->getCast(); + for (const auto& filterCast : cast_) { + bool found = false; + for (const auto& member : movieCast) { + if (stringContainsIgnoreCase(member, filterCast)) { + found = true; + break; + } + } + if (!found) { + return false; + } + } + } + + // Length (confronto stretto) + if (length_ != std::numeric_limits::max() && moviePtr->getLength() != length_) + return false; + + // Universe (match parziale, case-insensitive) + if (!universe_.empty() && !stringContainsIgnoreCase(moviePtr->getUniverse(), universe_)) + return false; + + return true; +} + + } // namespace media + + diff --git a/src/Media/Movie.h b/src/Media/Movie.h index 9f23113..19a50d7 100644 --- a/src/Media/Movie.h +++ b/src/Media/Movie.h @@ -17,11 +17,17 @@ class Movie : public Media { Movie(const std::string &title, int release, const std::string &language, bool favourite, const std::vector &genres, const std::string &img_path, const std::string ¬es, - const std::vector &cast, unsigned int length, - const std::string &universe); + const std::vector &cast = {}, unsigned int length = std::numeric_limits::max(), + const std::string &universe = ""); + bool operator==(const Media &other) const override; const std::vector &getCast() const; unsigned int getLength() const; const std::string &getUniverse() const; + + std::unique_ptr clone() const override; + + bool filter(const Media& movie) const override; }; } // namespace media #endif + diff --git a/src/Media/Novel.cpp b/src/Media/Novel.cpp index 2f21c7e..361585c 100644 --- a/src/Media/Novel.cpp +++ b/src/Media/Novel.cpp @@ -9,9 +9,18 @@ Novel::Novel(const std::string& title, int publicationYear, const std::string& l : Media(title, publicationYear, language, favorite, genres, imagePath, notes), author_(author), publisher_(publisher), pages_(pages), series_(series), isbn_(isbn) {} -// Visitor -void Novel::accept(IConstMediaVisitor& v) const { - v.visit(*this); +bool Novel::operator==(const Media& other) const { + const Novel* otherNovel = dynamic_cast(&other); + if (otherNovel) { + return Media::operator==(*otherNovel) && author_ == otherNovel->author_ && + publisher_ == otherNovel->publisher_ && pages_ == otherNovel->pages_ && + series_ == otherNovel->series_ && isbn_ == otherNovel->isbn_; + } + return false; +} + +std::unique_ptr Novel::clone() const { + return std::make_unique(*this); } // Getters @@ -28,4 +37,38 @@ void Novel::setPages(unsigned int pages) { pages_ = pages; } void Novel::setSeries(const std::string& series) { series_ = series; } void Novel::setIsbn(const std::string& isbn) { isbn_ = isbn; } + +bool Novel::filter(const Media& input) const { + // Riutilizzo filtro base di Media + if (!Media::filter(input)) + return false; + // Cast to Novel to access Novel-specific members + const Novel* novelPtr = dynamic_cast(&input); + if (!novelPtr) + return false; + + // Match fields + // Autore + if (!author_.empty() && !stringContainsIgnoreCase(novelPtr->getAuthor(), author_)) + return false; + + // Editore + if (!publisher_.empty() && !stringContainsIgnoreCase(novelPtr->getPublisher(), publisher_)) + return false; + + // Serie + if (!series_.empty() && !stringContainsIgnoreCase(novelPtr->getSeries(), series_)) + return false; + + // ISBN + if (!isbn_.empty() && !stringContainsIgnoreCase(novelPtr->getIsbn(), isbn_)) + return false; + + // Pagine (confronto stretto) + if (pages_ != std::numeric_limits::max() && novelPtr->getPages() != pages_) + return false; + + return true; +} + } \ No newline at end of file diff --git a/src/Media/Novel.h b/src/Media/Novel.h index 8462a61..6fa0ad5 100644 --- a/src/Media/Novel.h +++ b/src/Media/Novel.h @@ -1,5 +1,5 @@ -#ifndef Romanzo_H -#define Romanzo_H +#ifndef MEDIA_ROMANZO_H +#define MEDIA_ROMANZO_H #include "Media.h" @@ -16,10 +16,10 @@ class Novel : public Media { public: Novel(const std::string& title, int publicationYear, const std::string& language, bool favorite, const std::vector& genres, const std::string& imagePath, const std::string& notes, - const std::string& author, const std::string& publisher, - unsigned int pages, const std::string& series, const std::string& isbn); + const std::string& author = "", const std::string& publisher = "", + unsigned int pages = std::numeric_limits::max(), const std::string& series = "", const std::string& isbn = ""); - void accept(IConstMediaVisitor& v) const override; + bool operator==(const Media& other) const override; // Getters std::string getAuthor() const; @@ -34,6 +34,11 @@ class Novel : public Media { void setPages(unsigned int pages); void setSeries(const std::string& series); void setIsbn(const std::string& isbn); + + std::unique_ptr clone() const override; + + bool filter(const Media &novel) const override; }; + } -#endif // Novel_H \ No newline at end of file +#endif // MEDIA_ROMANZO_H \ No newline at end of file diff --git a/src/Media/Series.cpp b/src/Media/Series.cpp index fb6c2a5..f0fa1a9 100644 --- a/src/Media/Series.cpp +++ b/src/Media/Series.cpp @@ -13,7 +13,44 @@ Series::Series(const std::string &title, int release, episodes_(episodes), seasons_(seasons), ended_(ended) {} +bool Series::operator==(const Media &other) const { + const Series *otherSeries = dynamic_cast(&other); + if (otherSeries) { + return Movie::operator==(*otherSeries) && episodes_ == otherSeries->episodes_ && + seasons_ == otherSeries->seasons_ && ended_ == otherSeries->ended_; + } + return false; +} + +std::unique_ptr Series::clone() const { + return std::make_unique(*this); +} + unsigned int Series::getEpisodes() const { return episodes_; } unsigned int Series::getSeasons() const { return seasons_; } bool Series::isEnded() const { return ended_; } + +bool Series::filter(const Media& input) const { + if (!Movie::filter(input)) + return false; + + const Series* seriesPtr = dynamic_cast(&input); + if (!seriesPtr) + return false; // Protegge da cast fallito + + // Episodes (confronto stretto) + if (episodes_ != std::numeric_limits::max() && seriesPtr->getEpisodes() != episodes_) + return false; + + // Seasons (confronto stretto) + if (seasons_ != std::numeric_limits::max() && seriesPtr->getSeasons() != seasons_) + return false; + + // Ended (confronto booleano) + if (ended_ && ended_ != seriesPtr->isEnded()) + return false; + + return true; +} + } // namespace media diff --git a/src/Media/Series.h b/src/Media/Series.h index 91b96b0..73fa611 100644 --- a/src/Media/Series.h +++ b/src/Media/Series.h @@ -14,11 +14,16 @@ class Series : public Movie { bool favourite, const std::vector &genres, const std::string &img_path, const std::string ¬es, const std::vector &cast, unsigned int length, - const std::string &universe, unsigned int episodes, - unsigned int seasons, bool ended); + const std::string &universe, unsigned int episodes = std::numeric_limits::max(), + unsigned int seasons = std::numeric_limits::max(), bool ended = false); + bool operator==(const Media &other) const override; unsigned int getEpisodes() const; unsigned int getSeasons() const; bool isEnded() const; + + std::unique_ptr clone() const override; + + bool filter(const Media& input) const override; }; -} // namespace media -#endif +} +#endif // MEDIA_SERIES_H diff --git a/src/Media/StringUtils.h b/src/Media/StringUtils.h new file mode 100644 index 0000000..9d52635 --- /dev/null +++ b/src/Media/StringUtils.h @@ -0,0 +1,20 @@ +#ifndef MEDIA_STRINGUTILS_H +#define MEDIA_STRINGUTILS_H + +#include +#include +#include + +namespace media { +inline std::string toLowerCase(const std::string& str) { + std::string lower = str; + std::transform(lower.begin(), lower.end(), lower.begin(), + [](unsigned char c){ return std::tolower(c); }); + return lower; +} + +inline bool stringContainsIgnoreCase(const std::string& text, const std::string& pattern) { + return toLowerCase(text).find(toLowerCase(pattern)) != std::string::npos; +} +} +#endif // MEDIA_STRINGUTILS_H diff --git a/src/MediaLibrary.pro b/src/MediaLibrary.pro new file mode 100644 index 0000000..4fd055a --- /dev/null +++ b/src/MediaLibrary.pro @@ -0,0 +1,39 @@ +###################################################################### +# Automatically generated by qmake (3.1) Mon May 19 16:59:27 2025 +###################################################################### + +TEMPLATE = app +TARGET = MediaLibrary +INCLUDEPATH += . +QT += widgets + +# You can make your code fail to compile if you use deprecated APIs. +# In order to do so, uncomment the following line. +# Please consult the documentation of the deprecated API in order to know +# how to port your code away from it. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +# Input +HEADERS += Media/Album.h \ + Media/AudioBook.h \ + Media/Ebook.h \ + Media/IConstMediaVisitor.h \ + Media/IMedia.h \ + Media/Media.h \ + Media/Movie.h \ + Media/Novel.h \ + Media/Series.h \ + Memory/Database.h \ + Memory/Deserializer.h \ + Memory/MediaContainer.h \ + Memory/Serializer.h +SOURCES += main.cpp \ + Media/Album.cpp \ + Media/AudioBook.cpp \ + Media/Ebook.cpp \ + Media/Media.cpp \ + Media/Movie.cpp \ + Media/Novel.cpp \ + Media/Series.cpp \ + Memory/Database.cpp diff --git a/src/Memory/Database.cpp b/src/Memory/Database.cpp new file mode 100644 index 0000000..a205b2b --- /dev/null +++ b/src/Memory/Database.cpp @@ -0,0 +1,45 @@ +#include "Database.h" + +#include +#include + +#include "Deserializer.h" +namespace memory { +Database::~Database() { + close(false); // di default non salvare eventuali cambiamenti +} +bool Database::open(const QString &path) { + QFile file(path); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + return false; + } + media_container_.addMedia(Deserializer::deserialize(file)); + file.close(); + return true; +} +bool Database::close(bool save_on_exit) { + if (save_on_exit) { + return file_.commit(); // false <=> errore + } + file_.cancelWriting(); + return true; +} + +bool Database::save() { + if (!file_.commit()) { + // errore in scrittura + return false; + } + + if (!file_.open(QIODevice::ReadOnly | QIODevice::Text)) { + return false; + } + return true; +} + +std::vector> Database::filterMedia( + const media::Media &media_as_filter) { + return media_container_.filter(media_as_filter); +} + +} // namespace memory diff --git a/src/Memory/Database.h b/src/Memory/Database.h new file mode 100644 index 0000000..ea95c0a --- /dev/null +++ b/src/Memory/Database.h @@ -0,0 +1,24 @@ +#ifndef MEMORY_DATABASE_H +#define MEMORY_DATABASE_H +#include + +#include "./MediaContainer.h" +#include + +namespace memory { +class Database { + private: + MediaContainer media_container_; + QSaveFile file_; + + public: + ~Database(); + + bool open(const QString &path); + bool close(bool save); + bool save(); + + std::vector> filterMedia(const media::Media &); +}; +} // namespace memory +#endif diff --git a/src/Memory/Deserializer.h b/src/Memory/Deserializer.h index c86b172..fb074c9 100644 --- a/src/Memory/Deserializer.h +++ b/src/Memory/Deserializer.h @@ -1,16 +1,17 @@ #ifndef MEMORY_DESERIALIZER_H #define MEMORY_DESERIALIZER_H #include + #include "../Media/Media.h" namespace memory { class Deserializer { private: - static int vecToJSON(const std::vector &, QFile &); - static int vecToXML(const std::vector &, QFile &); + static std::vector>& XMLtoVec(const QFile &){} + static std::vector>& JSONtoVec(const QFile &){} public: - static int deserialize(const std::vector &, QFile &); + static std::vector>& deserialize(const QFile &){} }; } // namespace memory #endif diff --git a/src/Memory/MediaContainer.cpp b/src/Memory/MediaContainer.cpp new file mode 100644 index 0000000..1cff655 --- /dev/null +++ b/src/Memory/MediaContainer.cpp @@ -0,0 +1,108 @@ +#include "MediaContainer.h" +#include +#include + +namespace memory { + +void MediaContainer::addMedia(const media::Media& media) { + std::unique_ptr clone = media.clone(); + media::Media* rawPtr = clone.get(); + + // Inserisce rawPtr nel vettore "All" copiando il puntatore (non l’oggetto!) + data_[static_cast(Type::All)].push_back(std::unique_ptr(clone->clone())); + + // Inserisco anche nel tipo specifico + Type t = detectType(*clone); + if (t != Type::All) { + data_[static_cast(t)].push_back(std::move(clone)); + } +} + + +MediaContainer::Type MediaContainer::detectType(const media::Media& media) const { + if (dynamic_cast(&media)) return Type::Series; + if (dynamic_cast(&media)) return Type::AudioBook; + if (dynamic_cast(&media)) return Type::Ebook; + if (dynamic_cast(&media)) return Type::Movie; + if (dynamic_cast(&media)) return Type::Album; + if (dynamic_cast(&media)) return Type::Novel; + return Type::All; +} + +void MediaContainer::removeMedia(const media::Media& media) { + for (auto& vec : data_) { + vec.erase(std::remove_if(vec.begin(), vec.end(), + [&](const std::unique_ptr& m) { + return typeid(*m) == typeid(media) && *m == media; + }), vec.end()); + } +} + +void MediaContainer::clear() { + for (auto& vec : data_) { + vec.clear(); + } +} + +std::vector MediaContainer::getAll() const { + return getByType(Type::All); +} + +std::vector MediaContainer::getByType(Type type) const { + std::vector result; + for (const auto& ptr : data_[static_cast(type)]) { + result.push_back(ptr.get()); + } + return result; +} + +std::vector MediaContainer::getByGroup(Type type) const { + std::vector result; + + auto appendGroup = [&](Type t) { + for (const auto& ptr : data_[static_cast(t)]) { + result.push_back(ptr.get()); + } + }; + + switch (type) { + case Type::Novel: + appendGroup(Type::Novel); + appendGroup(Type::Ebook); + appendGroup(Type::AudioBook); + break; + case Type::Movie: + appendGroup(Type::Movie); + appendGroup(Type::Series); + break; + case Type::All: + appendGroup(Type::All); + break; + default: + appendGroup(type); + break; + } + + return result; +} + +std::vector MediaContainer::filter(const media::Media& media) const { + std::vector results; + Type t = detectType(media); + for (const media::Media* m : getByGroup(t)) { + if (media.filter(*m)) { + results.push_back(m); + } + } + return results; +} + +int MediaContainer::serialize(QSaveFile& file) const { + std::vector rawAll; + for (const auto& ptr : data_[static_cast(Type::All)]) { + rawAll.push_back(ptr.get()); + } + return Serializer::Serialize(rawAll, file); +} + +} // namespace memory diff --git a/src/Memory/MediaContainer.h b/src/Memory/MediaContainer.h index cc24df4..9ff668e 100644 --- a/src/Memory/MediaContainer.h +++ b/src/Memory/MediaContainer.h @@ -1,14 +1,54 @@ -#ifndef MEMORY_MEDIA_CONTAINER_H -#define MEMORY_MEDIA_CONTAINER_H +#ifndef MEMORY_MEDIACONTAINER_H +#define MEMORY_MEDIACONTAINER_H + +#include +#include +#include +#include + #include "../Media/Media.h" +#include "../Media/Novel.h" +#include "../Media/Album.h" +#include "../Media/Movie.h" +#include "../Media/Ebook.h" +#include "../Media/AudioBook.h" +#include "../Media/Series.h" +#include "Serializer.h" namespace memory { + class MediaContainer { - public: - MediaContainer() = default; - int addMedia(media::Media *); - int removeMedia(media::Media *); - std::vector filter(media::Media *); +private: + enum class Type { + All = 0, + Novel, + Album, + Movie, + Ebook, + AudioBook, + Series, + TypeCount + }; + + std::array>, static_cast(Type::TypeCount)> data_; + + Type detectType(const media::Media& media) const; + + std::vector getByType(Type type) const; + std::vector getByGroup(Type type) const; + +public: + void addMedia(const media::Media& media); + void removeMedia(const media::Media& media); + void clear(); + + std::vector filter(const media::Media& media) const; + + std::vector getAll() const; + + int serialize(QSaveFile& file) const; }; + } // namespace memory -#endif + +#endif // MEMORY_MEDIACONTAINER_H diff --git a/src/Memory/Serializer.h b/src/Memory/Serializer.h index f34aad0..cecc7d7 100644 --- a/src/Memory/Serializer.h +++ b/src/Memory/Serializer.h @@ -1,17 +1,17 @@ #ifndef MEMORY_SERIALIZER_H #define MEMORY_SERIALIZER_H -#include - +#include #include "../Media/Media.h" namespace memory { class Serializer { + private: - static std::vector& XMLtoVec(const QFile &); - static std::vector& JSONtoVec(const QFile &); + static int vecToJSON(const media::Media &, QSaveFile &){} + static int vecToXML(const media::Media&, QSaveFile &){} public: - static std::vector& serialize(const QFile &); + static int Serialize(std::vector, QSaveFile &){} }; } // namespace memory #endif diff --git a/src/main.cpp b/src/main.cpp index 76e8197..4a96007 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1 +1,10 @@ -int main() { return 0; } +#include +#include +#include +#include +#include "Media/Media.h" // Include il tuo header + +int main() { + std::cout << "Aggiornato" << std::endl; + return 0; +} diff --git a/src/src.pro b/src/src.pro index 131b69f..ba5f2c5 100644 --- a/src/src.pro +++ b/src/src.pro @@ -1,5 +1,5 @@ ###################################################################### -# Automatically generated by qmake (3.1) Mon May 19 10:58:10 2025 +# Automatically generated by qmake (3.1) Tue May 20 17:32:43 2025 ###################################################################### TEMPLATE = app @@ -24,7 +24,11 @@ HEADERS += Media/Album.h \ Media/Movie.h \ Media/Novel.h \ Media/Series.h \ - Memory/MediaContainer.h + Media/StringUtils.h \ + Memory/Database.h \ + Memory/Deserializer.h \ + Memory/MediaContainer.h \ + Memory/Serializer.h SOURCES += main.cpp \ Media/Album.cpp \ Media/AudioBook.cpp \ @@ -32,4 +36,6 @@ SOURCES += main.cpp \ Media/Media.cpp \ Media/Movie.cpp \ Media/Novel.cpp \ - Media/Series.cpp + Media/Series.cpp \ + Memory/Database.cpp \ + Memory/MediaContainer.cpp