Page 1 of 3 123 LastLast
Results 1 to 20 of 54

Thread: Integration: Nested Tree Parent Child C++ Classes with Models/Delegates for QML

  1. #1
    Join Date
    Dec 2016
    Posts
    46
    Thanks
    20
    Qt products
    Qt5
    Platforms
    Windows

    Smile Integration: Nested Tree Parent Child C++ Classes with Models/Delegates for QML

    Hi!

    I have been using Qt the last couple of months for a class project and I am really loving it especially the QML part of it. It really is exactly what I would like to work with. However, I have gotten stuck at a certain obsticle the last couple of weeks and I would really appreciate some help with it.

    The application that I am building is basically an interface to manage, sort and filter through Pokémon cards in the users collection. The user creates a new Pokémon cards album and populates it with Pokémon Cards.

    Here is how the UI looks like:


    For example:
    The user creates two albums, one called "Favorites" and another called "Wishlist". The user can then add cards to those Albums. Once that is done, the user will be able to view the available albums in a tab or a page and clicking on an album will open up a view that display the cards in that album.

    I have found different ways to go about this implementation. One of them uses a TreeItem class and TreeModel class to create this nested QList of objects. The problem is that I will need to have different classes with different properties and children depending on where they are in the Tree. Here is a diagram I made to show what I mean:


    Since the Card objects won't exist outside of Albums, I have decided to pass them to the Albums directly rather than using pointers. However, this means that appending a card to an Album will demand a copy constructor if I use the following method:
    Qt Code:
    1. avoid Album::addCard(const Card &scarf)
    2. {
    3. BeginInsertRows();
    4. m_cards << card;
    5. EndInsertRows();
    6. }
    To copy to clipboard, switch view to plain text mode 

    The problem here is that I keep running into problems with the creating the Copy constructor and any methods that I need to add to the class to make the constructor work.
    So here is how the approach that I took looks like:

    main.cpp:
    I included the three header files for the classes App, Album and Card and registered them using qmlregistertype. I also created an instance of the App class and set it as root context property to use the models later on.

    App:
    This class basically fulfills the uppermost parent in the tree. It has no properties such as name and so on. Just the minimal tree root data methods to add and remove Albums to and from it on run time in it's QList<Album> m_album private member. It also has a NameRole to get the name of the Albums it contains.

    Album:
    It is added to an App object instance. It points to it's parent through a private App* m_parentApp variable. It has a QString m_name and it can add cards to it's QList<Card>m_cards private list. It also has several Roles used to retrieve information about cards in it using the data method.

    Card:
    It is added to Albums, has no list of children. Points to it's parent Album. Has many variables such as Name, ID, ImageURL and so on.

    All the classes inherit QAbstractListModel publicly. Not sure if they really should but that's what I have found people recommending on threads.

    The problem with creating the copy constructor (Album(const Album &source) is that when I am adding an Album to an App (m_albums << album) is this:
    I am not really sure how to go about iteratating through the children appended to the object being copied.

    I created a for() loop that ends at m_cards.count(). Then I noticed that I needed a way to access the card data in the Album being copied for each iteration but I have found no way to make it work. Using the source.data(index, role) expects a QmlIndex rather than an int. I tried dynamic_casting, not sure if I should but that didn't work either so I thought that I should create a new method that retrieves the Card from the Album by value or reference so that my copy constructor works but haven't had any success there.
    I tried:
    Qt Code:
    1. Card getCard(int row)
    2. {
    3. Return m_cards.at(row);
    To copy to clipboard, switch view to plain text mode 
    }
    But that didn't work, I tried using Card* and Card& as well as m_cards[index.row()] but that didn't work.
    The only reason I am doing this is so that my copy constructor which is automatically called when appending an album to and App or a Card to an Album can do something like this:
    Qt Code:
    1. For all the children in the objects QList:
    2. This->name = source.m_cards.name();
    To copy to clipboard, switch view to plain text mode 

    I would appreciate some help with this. Feel free to give any feedback about the approach or suggest a different too if you think that something else would be better.

    Thanks.

  2. #2
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,419
    Thanks
    37
    Thanked 1,546 Times in 1,496 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Integration: Nested Tree Parent Child C++ Classes with Models/Delegates for QML

    There are multiple options for this.

    1) You could have an internal data structure and have a model that presents the album "view" on the data and models that present the card "view" of the data.
    Depending on whether you can show multiple albums at the same time, you might need more than one instance of the latter.

    2) Another option is to make some of the data classes themselves into models themselves, e.g. the "Album" class and the "App" class.

    3) The "App" class could also be just a normal QObject derived class and have the "Album" models as a list property.

    Option (1) requires separate classes for data and models, but also allows the data classes to be copyable.
    I.e. more classes and thus more core, but treating data separately from the QML adapter to the data.

    Options (2) and (3) need at least the "Album" class as a QAbstractListModel subclass, so a QList<Album*> as the container in "App".

    When you write "all classes inherit QAbstractListModel" it looks like your chosen approach is (2), but do you also mean "Card" is a list model?

    Cheers,
    _

  3. The following user says thank you to anda_skoa for this useful post:

    Nizars (30th December 2016)

  4. #3
    Join Date
    Dec 2016
    Posts
    46
    Thanks
    20
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Integration: Nested Tree Parent Child C++ Classes with Models/Delegates for QML

    Hi Anda,

    Thanks for reading the problem I am having and I appreciate the overview of the different options I have.

    My goal is to develop the application further and add the ability to search through the albums, sort by a specific variable and possibly even drag and drop a card to a different Album.

    The more important function however is the ability to save the "session" to a local file and load from it on start up. It could be a parent class to App called AppManager that has the methods ExportLibrary and ImportLibrary to and from a local file. I have not decided on a format for the data yet, I am really open for anything.

    I am mentioning this to help narrow down the more appropriate path to take for the data structure. Once I have gotten the current obsticle fixed and learned how to implement it, I will change the root context property from App to AppManager and have it provide the App instance to the application.

    I assume that this narrows down my options to option 1 for the most suitable data structure which is having the data classes separate from the from the models.

    The Card class shouldn't inherit publicly from QAbstractListModel. That was a mistake from my part. It however should be registered and made available to the QML to help instanciate Card objects for the Albums.

    What do you think, does it sound right?

    Cheers.

  5. #4
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,419
    Thanks
    37
    Thanked 1,546 Times in 1,496 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Integration: Nested Tree Parent Child C++ Classes with Models/Delegates for QML

    I don't see anything that would narrow your option down to just (1), however, it is often benefitial to not design data structures and data handling with just the UI's needs in mind.

    Lets look at this with a simplied example, an address book:

    1) for that I would have
    * a Contact class that can hold all data for a single address book entry
    * an AddressBook class that has a list or maybe even a hash of Contact objects and which would have methods to add/remove/change/get/list contacts

    2a) a list model that gets a pointer to an AddressBook and provides the list of contacts, contact details as roles

    2b) an Import/Export class or classes that also get an AddressBook pointer or reference and implement data I/O

    3) optionally, a Contact adapter/editor class that serves as an QML adapter for modifying a single contact. It would get a Contact object and provide its data as separate Q_PROPERTY fields, it can provide methods to check for validity of the data, etc.

    (2a) and (2b) are different usages of the data but can still work on the same data. the base classes only need to ensure they can provide all the functionality required for these two use cases.

    For your application I wonder if you really want cards nested inside albums.
    I.e. is an Album not just a "view" of cards, a selection from the whole?
    For example could a user have "All my cards", "All time favorites", "Favorite Water Pokemons", with the same "Vaporeon" card being in all three?

    Cheers,
    _

  6. The following user says thank you to anda_skoa for this useful post:

    Nizars (30th December 2016)

  7. #5
    Join Date
    Dec 2016
    Posts
    46
    Thanks
    20
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Integration: Nested Tree Parent Child C++ Classes with Models/Delegates for QML

    You make a good point!
    I didn't really think of that. The thing is, for now at least and to narrow down my project, I have decided to work only with one set of Pokemon cards. Those cards exist in <cardID>.json files in a resource. Those JSON documents contain all the variable values for the cards such name, hp, attacks and so on. The card images exist in another folder in the resources as <cardID>.jpg. I have done this so that I have something to work with and not risk spending a month or two working with network, ssl, cache, json classes and risk not having anything to present as the deadline aproaches. I do like the project I am working with and I am planning to add those functionalities in the future, maybe even a function that adds cards by scanning them with a phone camera. The JSON documents are retreived from: pokemontcg.io but that is something that I won't touch until the main application fully works.

    My line of thinking has been that when the user wants to add a card to an album. He or she will type the name or the id of the card and the program creates an instance of that card in the album. If he doesn't add it to the album and decided just to see it, it will be deleted once he exits the view. I also thought of having an instance of all the cards pre-loaded in a hidden default album that the App uses to display the cards before the user adds them to his or her Album.

    You make a good point about a Card being available in more than one album. I guess there should be a default "All my cards" Album. I guess cards in that Album determines what cards are made available to the other albums. I assume that this would be a bit problematic if the user wants to create a "My wishlist" or "To buy" Album. There is also the problem of duplicate cards.

    I will try to rethink the relationships between the Albums and between the Cards and Albums. I think that having an Album as an isolated container of cards from other Cards in other Albums might make the implementation a bit easier assuming that the user will manually add Cards to Albums and not expect them to be shared among the Albums. I can however create a "view" that shows all the cards in all the albums or multiple Albums.

  8. #6
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,419
    Thanks
    37
    Thanked 1,546 Times in 1,496 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Integration: Nested Tree Parent Child C++ Classes with Models/Delegates for QML

    Just sketching some ideas here:

    Qt Code:
    1. class Card
    2. {
    3. QString id;
    4. QString name;
    5. // ....
    6. };
    7.  
    8. class CardManager : public QObject
    9. {
    10. Q_OBJECT
    11.  
    12. public:
    13. // returns an invalid card if ID is not found, e.g. Card object with empty "id"
    14. Card addCardById(const QString &id);
    15. Card addCardByName(const QString &name);
    16.  
    17. Card card(const QString &id) const;
    18. QList<Card> cards() const;
    19.  
    20. int count() const;
    21.  
    22. signals:
    23. void cardAdded(const QString &id);
    24. void cardRemoved(const QString &id);
    25.  
    26. private:
    27. QList<Card> m_cards;
    28. };
    To copy to clipboard, switch view to plain text mode 

    Qt Code:
    1. class Album
    2. {
    3. QString id;
    4. QString name;
    5. QStringList cardIDs;
    6. };
    7.  
    8. class AlbumManager : public QObject
    9. {
    10. Q_OBJECT
    11. public:
    12. Album createAlbum(const QString &name);
    13.  
    14. Album album(const QString &id) const;
    15.  
    16. QList<Album> albums() const;
    17.  
    18. int count() const;
    19.  
    20. void addCard(const QString &albumId, const QString &cardId);
    21. void removeCard(const QString &albumId, const QString &cardId);
    22.  
    23. signals:
    24. void albumAdded(const QString &id);
    25. void albumRemoved(const QString &id);
    26.  
    27. void cardAdded(const QString &albumId, const QStringList &cardIDs);
    28. void cardRemoved(const QString &albumId, const QStringList &cardIDs);
    29. };
    To copy to clipboard, switch view to plain text mode 

    Qt Code:
    1. class AbstractCardModel : public QAbstractListModel
    2. {
    3. Q_OBJECT
    4. public:
    5. enum Roles {
    6. IdRole = Qt::UserRole + 1,
    7. NameRole,
    8. // ....
    9. }
    10.  
    11. explicit AbstractCardModel(CardManager *cardManager, QObject *parent = 0);
    12.  
    13. // this uses cardForIndex to get the card, then uses role to return the actual data
    14. QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
    15.  
    16. protected:
    17. QHash<int, QByteArray> roleNames() const;
    18.  
    19. virtual Card cardForIndex(const QModelIndex &index) const = 0;
    20.  
    21. protected:
    22. CardManager *m_cardManager;
    23. };
    To copy to clipboard, switch view to plain text mode 
    Qt Code:
    1. // for showing the cards of a single album
    2. class AlbumCardsModel : public AbstractCardsModel
    3. {
    4. Q_OBJECT
    5. public:
    6. AlbumCardsModel(AlbumManager *albumManager, CardManager *cardManager, QObject *parent = 0);
    7.  
    8. void showAlbum(const QString &albumId);
    9.  
    10. int rowCount(const QModelIndex &parent) const;
    11.  
    12. protected:
    13. Card cardForIndex(const QModelIndex &index) const;
    14.  
    15. private slots:
    16. // gets connected to m_albumManager's albumRemoved() signal
    17. void onAlbumRemoved(const QString &albumId);
    18.  
    19. void onCardAdded(const QString &albumId, const QString cardId);
    20. void onCardRemoved(const QString &albumId, const QString cardId);
    21.  
    22. private:
    23. AlbumManager *m_albumManager;
    24. Album m_album;
    25. };
    26.  
    27. void AlbumCardsModel::showAlbum(const QString &albumId)
    28. {
    29. beginResetModel();
    30.  
    31. m_album = m_albumManager->album(albumId);
    32.  
    33. endResetModel();
    34. }
    35.  
    36. int AlbumCardsModel::rowCount(const QModelIndex&) const
    37. {
    38. return m_album.cardIDs.count();
    39. }
    40.  
    41. Card AlbumCardsModel::cardForIndex(const QModelIndex &index) const
    42. {
    43. return m_cardManager->card(m_album.cardIDs.at(index.row());
    44. }
    45.  
    46. void AlbumCardsModel::onAlbumRemoved(const QString &albumId)
    47. {
    48. if (albumId != m_album.id) return;
    49.  
    50. beginResetModel();
    51. m_album = Album();
    52. endResetModel();
    53. }
    54.  
    55. void AlbumCardsModel::onCardAdded(const QString &albumId, const QString &cardId)
    56. {
    57. if (albumId != m_album.id) return;
    58.  
    59. const Album updatedAlbum = m_albumManager->album(albumId);
    60. const int row = updatedAlbum.cardIDs.indexOf(cardId);
    61.  
    62. beginInsertRows(QModelIndex(), row, row);
    63.  
    64. m_album = updatedAlbum;
    65.  
    66. endInsertRows();
    67. }
    68.  
    69. void AlbumCardsModel::onCardRemoved(const QString &albumId, const QString &cardId)
    70. {
    71. if (albumId != m_album.id) return;
    72.  
    73. const Album updatedAlbum = m_albumManager->album(albumId);
    74. const int row = m_album.cardIDs.indexOf(cardId);
    75.  
    76. beginRemoveRows(QModelIndex(), row, row);
    77.  
    78. m_album = updatedAlbum;
    79.  
    80. endRemoveRows();
    81. }
    To copy to clipboard, switch view to plain text mode 

    Cheers,
    _

  9. The following 2 users say thank you to anda_skoa for this useful post:

    d_stranz (30th December 2016), Nizars (30th December 2016)

  10. #7
    Join Date
    Dec 2016
    Posts
    46
    Thanks
    20
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Integration: Nested Tree Parent Child C++ Classes with Models/Delegates for QML

    I really appreciate your time and all the help you are offering me on this!

    I have a quick question for you while I finish making changes to my classes.

    What is the role of a <class>Manager class? I am just trying to understand how it fits in.
    Say I want to to add copy constractors and assignment opperators for the App, Album and Card classes, where would those be implemented? in their respective classes? or in the their accompanying <class>Manager classes?
    What about the Setter and Getter class methods such as "QString getCardName() const;"? Same with the default and overloaded constructors? should I even have a default constructor in the original class?

    I have noticed that you combine each class and it's Manager class in the same document. Is there a reason or a benifit behind this practise? or is this simple down to preference and time saving?
    I have created three different classes for each of the "core" classes. An Album class, an AlbumsManager class and an AlbumModel class. I am totally open to changing it to the template you wrote if it makes a difference.

  11. #8
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    4,721
    Thanks
    259
    Thanked 760 Times in 750 Posts
    Qt products
    Qt5
    Platforms
    Windows Android

    Default Re: Integration: Nested Tree Parent Child C++ Classes with Models/Delegates for QML

    Yes, anda_skoa has been very generous with his help on this one and has given you a well-thought-out and flexible design.

    If you use the Card and Album classes as anda_skoa has defined them in his code, you don't actually need an explicit copy constructor (or even an assignment operator) because C++ will implement default ones for you. Usually default constructor / assignment does a bitwise copy of the right-hand side instance (i.e. the instance you are copying from), except when the class being copied contains member variables which themselves have copy / assignment operators, which QString and QStringList do (and which fundamental types like int, float, etc. also have). If you add anything to the definitions of these classes which does not have explicit copy / assignment, you'll either have to make copy and assignment methods for them, or implement them in the Card or Album class. For example, if you add a pointer variable, you'll probably want to either wrap it in a smart pointer (which has copy / assignment), make a deep copy of the contents of the instance pointed to, or add another "manager" which is in charge of the lifetime of these pointers (rather than delete them in the Card or Album destructor).

    Combining the Card and CardManager class in the same file is basically just for convenience. More importantly, only the CardManager should be allowed to create Card instances, because then it will automatically add them to the list of Card instances it is managing. Likewise for Album and AlbumManager. You can't have a standalone, unmanaged Card or Album. But on the other hand, anda_skoa's design allows for cards that belong to no album as well as cards that belong to multiple albums.

    You'll probably only have one instance each of the AlbumManager and CardManager classes, but the design also anticipates that you might want to expand to handle multiple users, each one of whom will have their own card and album collections, so you'd need a card and album manager for each of them.

    The AlbumManager and CardManager classes are the GUI-independent classes that are used by the AlbumCardsModel. This model is the interface to the views; when either the CardManager or AlbumManager make changes to their content, they emit signals that the model listens for so it can in turn update the views. You might have several instances of AlbumCardsModel - one for interfacing to one or more views of different albums.
    Last edited by d_stranz; 31st December 2016 at 02:02.
    <=== The Great Pumpkin says ===>
    Please use CODE tags when posting source code so it is more readable. Click "Go Advanced" and then the "#" icon to insert the tags. Paste your code between them.

  12. The following user says thank you to d_stranz for this useful post:

    Nizars (31st December 2016)

  13. #9
    Join Date
    Dec 2016
    Posts
    46
    Thanks
    20
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Integration: Nested Tree Parent Child C++ Classes with Models/Delegates for QML

    Thanks Stanz for your feedback and for the clarifications, I really appreciate it.

    I have been working with this project all day so I will need to take a break rest my eyes and shoulders a bit. I have come quite a bit now with the classes. There are a few errors left and I am sure that there is unnecessary, repeated or misplaced code too. I will read through it all again tomorrow and try to learn the proper implementations and correct the code.

    For now, here is the code I've written so far in case you want to have a look at it. I don't expect any of you to go through it and make corrections, you have done more than enough. But if you want to point out something that I have misunderstood I would gladly have a look at it again.

    Qt Code:
    1. // AbstractCardModel.h
    2. #include "cardsmanager.h"
    3. #include "card.h"
    4.  
    5. class AbstractCardModel : public QAbstractListModel
    6. {
    7. Q_OBJECT
    8. public:
    9. enum AlbumRoles { CardIDRole = Qt::UserRole + 1, NameRole, ImageURLRole, SubtypeRole, SupertypeRole, NumberRole, ArtistRole, RarityRole, SeriesRole, SetRole, SetCodeRole, ConditionRole, StatusRole};
    10. explicit AbstractCardModel(CardsManager *cardsManager, QObject *parent = 0);
    11.  
    12. // this uses cardForIndex to get the card, then uses role to return the actual data
    13. QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
    14.  
    15. protected:
    16. QHash<int, QByteArray> roleNames() const;
    17. virtual Card cardForIndex(const QModelIndex &index) const = 0;
    18.  
    19. protected:
    20. CardsManager *m_cardsManager;
    21. };
    22.  
    23. #endif //ABSTRACTCARDMODEL_H
    To copy to clipboard, switch view to plain text mode 

    Qt Code:
    1. // AbstractCardModel.cpp
    2. #include "abstractcardmodel.h"
    3.  
    4. AbstractCardModel::AbstractCardModel(CardsManager *cardsManager, QObject *parent)/*: QObject(parent)*/
    5. {
    6. this->m_cardsManager = cardsManager;
    7. }
    8.  
    9. QVariant AbstractCardModel::data(const QModelIndex &index, int role) const
    10. {
    11. // if (index.row() < 0 || index.row() >= this->m_cards.count())
    12. // return QVariant();
    13.  
    14. const Card &card = cardForIndex(index);
    15. if (role == CardIDRole)
    16. return card.getCardID();
    17. else if (role == NameRole)
    18. return card.getName();
    19. else if (role == ImageURLRole)
    20. return card.getImageURL();
    21. else if (role == SubtypeRole)
    22. return card.getSubtype();
    23. else if (role == SupertypeRole)
    24. return card.getSupertype();
    25. else if (role == NumberRole)
    26. return card.getNumber();
    27. else if (role == ArtistRole)
    28. return card.getArtist();
    29. else if (role == RarityRole)
    30. return card.getRarity();
    31. else if (role == SeriesRole)
    32. return card.getSeries();
    33. else if (role == SetRole)
    34. return card.getSet();
    35. else if (role == SetCodeRole)
    36. return card.getSetCode();
    37. else if (role == ConditionRole)
    38. return card.getCondition();
    39. else if (role == StatusRole)
    40. return card.getStatus();
    41. return QVariant();
    42. }
    To copy to clipboard, switch view to plain text mode 

    Qt Code:
    1. // Album.h
    2. class Album
    3. {
    4. private:
    5. QList<Card> cards;
    6. QString albumId;
    7. QString albumName;
    8. int nrOfCards;
    9.  
    10. protected:
    11. QHash<QString, int> nameToId() const;
    12.  
    13. public:
    14. // Default Constructor
    15. Album(/*QObject *parent = 0*/);
    16.  
    17. // Overloaded Constructor
    18. Album(QString newAlbumName);
    19.  
    20. // Copy Constructor
    21. Album(const Album& source);
    22.  
    23. // Assignment Opperator
    24. Album& operator=(const Album& source);
    25.  
    26. // ALBUM GETTERS
    27. QString getAlbumName() const;
    28. QString getAlbumId() const;
    29. int getNrOfCards() const;
    30.  
    31. // ALBUM SETTERS
    32. void setAlbumName(const QString newAlbumName);
    33. void setAlbumId(const QString newAlbumId);
    34. void setNrOfCards(const int newNrOfCards);
    35.  
    36. // CARDS IN ALBUM
    37. void addCard(const Card& source);
    38. void addCardById(const QString &id);
    39. void addCardByName(const QString &newName);
    40.  
    41. void removeCard(const int index);
    42. Card/*&*/ getCard(const int index);
    43.  
    44. // Destructor
    45. ~Album();
    46. };
    To copy to clipboard, switch view to plain text mode 

    Qt Code:
    1. // Album.cpp
    2. #include "album.h"
    3.  
    4. // Default Constructor
    5. Album::Album(/*QObject *parent*/)/*:QAbstractListModel(parent)*/
    6. {
    7. this->albumName = "Default Album Name";
    8. this->albumId = "DefaultAlbumID";
    9. this->nrOfCards = 0;
    10. }
    11.  
    12. // Overloaded Constructor
    13. Album::Album(QString newAlbumName)
    14. {
    15. this->albumName = newAlbumName;
    16. this->albumId = "DefaultAlbumID";
    17. this->nrOfCards = 0;
    18. }
    19.  
    20. // Copy Constructor
    21. Album::Album(const Album& source)
    22. {
    23. this->albumName = source.albumName;
    24. this->albumId = source.albumId;
    25. this->nrOfCards = source.nrOfCards;
    26. for(int i = 0; i < source.nrOfCards; i++)
    27. {
    28. this->addCard(Card(source.cards[i]));
    29. }
    30. }
    31.  
    32. // Assignment Opperator
    33. Album& Album::operator =(const Album& source)
    34. {
    35. if(this != &source)
    36. {
    37. this->albumName = source.albumName;
    38. this->albumId = source.albumId;
    39. this->nrOfCards = source.nrOfCards;
    40. for(int i = 0; i < source.nrOfCards; i++)
    41. {
    42. this->addCard(Card(source.cards[i]));
    43. }
    44. }
    45. return *this;
    46. }
    47.  
    48. // ALBUM GETTERS
    49. QString Album::getAlbumName() const
    50. {
    51. return albumName;
    52. }
    53.  
    54. QString Album::getAlbumId() const
    55. {
    56. return albumId;
    57. }
    58.  
    59. int Album::getNrOfCards() const
    60. {
    61. return cards.count();
    62. }
    63.  
    64. // ALBUM SETTERS
    65. void Album::setAlbumName(const QString newAlbumName)
    66. {
    67. this->albumName = newAlbumName;
    68. }
    69.  
    70. void Album::setAlbumId(const QString newAlbumId)
    71. {
    72. this->albumId = newAlbumId;
    73. }
    74.  
    75. void Album::setNrOfCards(const int newNrOfCards)
    76. {
    77. this->nrOfCards = newNrOfCards;
    78. }
    79.  
    80.  
    81. // CARDS IN ALBUM
    82. void Album::addCard(const Card& source)
    83. {
    84. cards.append(source);
    85. this->nrOfCards = cards.count();
    86. }
    87.  
    88. void Album::removeCard(const int index)
    89. {
    90. cards.removeAt(index);
    91. this->nrOfCards = cards.count();
    92. }
    93.  
    94. void Album::addCardById(const QString &id)
    95. {
    96. // Card info
    97. int number;
    98. QString nrString;
    99. QString name;
    100. QString cardId;
    101. QString subtype;
    102. QString supertype;
    103. QString artist;
    104. QString rarity;
    105. QString series;
    106. QString set;
    107. QString setCode;
    108. QString imageUrl;
    109. QString status;
    110. QString condition;
    111.  
    112. // Build file name
    113. QString fileName = ":/cards/Resources/JSON/xy7-";
    114. fileName.append(id);
    115. fileName.append(".json");
    116.  
    117. // Open file
    118. QFile file(fileName);
    119. if(!file.open(QFile::ReadOnly | QFile::Text))
    120. {
    121. qDebug() << "Error: Could not open file for reading";
    122. }
    123.  
    124. // Save file information in fileText
    125. QTextStream in(&file);
    126. QString fileText = in.readAll();
    127.  
    128. // Close file
    129. file.close();
    130.  
    131. // Create card jsonObject from fileText
    132. QJsonDocument jsonDocument = QJsonDocument::fromJson(fileText.toUtf8());
    133. QJsonObject rootObject = jsonDocument.object();
    134. QJsonValue value = rootObject.value(QString("card"));
    135. QJsonObject cardRootValues = value.toObject();
    136.  
    137. // Set values for card variables
    138. name = cardRootValues.value("name").toString();
    139. cardId = cardRootValues.value("id").toString();
    140. subtype = cardRootValues.value("subtype").toString();
    141. supertype = cardRootValues.value("supertype").toString();
    142. nrString = cardRootValues.value("number").toString();
    143. number = nrString.toInt();
    144. artist = cardRootValues.value("artist").toString();
    145. rarity = cardRootValues.value("rarity").toString();
    146. series = cardRootValues.value("series").toString();
    147. set = cardRootValues.value("set").toString();
    148. setCode = cardRootValues.value("setCode").toString();
    149. imageUrl = cardRootValues.value("imageURL").toString();
    150.  
    151. this->addCard(Card(cardId, name, imageUrl, subtype, supertype, number, artist, rarity, series, set, setCode, condition, status));
    152. }
    153.  
    154. void Album::addCardByName(const QString &newName)
    155. {
    156. // Card info
    157. QString status;
    158. QString condition;
    159.  
    160. // Build file name
    161. QString fileName = ":/cards/Resources/JSON/xy7-";
    162. QString id = nameToId().value(newName);
    163. fileName.append(id);
    164. fileName.append(".json");
    165.  
    166. // Open file
    167. QFile file(fileName);
    168. if(!file.open(QFile::ReadOnly | QFile::Text))
    169. {
    170. qDebug() << "Error: Could not open file for reading";
    171. return;
    172. }
    173.  
    174. // Save file information in fileText
    175. QTextStream in(&file);
    176. QString fileText = in.readAll();
    177.  
    178. // Close file
    179. file.close();
    180.  
    181. // Create card jsonObject from fileText
    182. QJsonDocument jsonDocument = QJsonDocument::fromJson(fileText.toUtf8());
    183. QJsonObject rootObject = jsonDocument.object();
    184. QJsonValue value = rootObject.value(QString("card"));
    185. QJsonObject cardRootValues = value.toObject();
    186.  
    187. // Set values for card variables
    188. QString name = cardRootValues.value("name").toString();
    189. QString cardId = cardRootValues.value("id").toString();
    190. QString subtype = cardRootValues.value("subtype").toString();
    191. QString supertype = cardRootValues.value("supertype").toString();
    192. QString nrString = cardRootValues.value("number").toString();
    193. int number = nrString.toInt();
    194. QString artist = cardRootValues.value("artist").toString();
    195. QString rarity = cardRootValues.value("rarity").toString();
    196. QString series = cardRootValues.value("series").toString();
    197. QString set = cardRootValues.value("set").toString();
    198. QString setCode = cardRootValues.value("setCode").toString();
    199. QString imageUrl = cardRootValues.value("imageURL").toString();
    200.  
    201. // Create Card instance from variables
    202. this->addCard(Card(cardId, name, imageUrl, subtype, supertype, number, artist, rarity, series, set, setCode, condition, status));
    203. }
    204.  
    205.  
    206. Card/*&*/ Album::getCard(const int index)
    207. {
    208. return this->cards[index];
    209. }
    210.  
    211. QHash<QString, int> Album::nameToId() const {
    212. QHash<QString, int> name;
    213. name["Oddish"] = 1;
    214. name["Gloom"] = 2;
    215. name["Vileplume"] = 3;
    216. name["Bellossom"] = 4;
    217. name["Spinarak"] = 5;
    218. name["Ariados"] = 6;
    219. name["Sceptile-EX"] = 7;
    220. name["M Sceptile-EX"] = 8;
    221. name["Combee"] = 9;
    222. name["Vespiquen"] = 10;
    223. name["Vespiquen"] = 11;
    224. name["Virizion"] = 12;
    225. name["Flareon"] = 13;
    226. name["Entei"] = 14;
    227. name["Entei"] = 15;
    228. name["Larvesta"] = 16;
    229. name["Volcarona"] = 17;
    230. name["Volcarona"] = 18;
    231. name["Magikarp"] = 19;
    232. name["Gyarados"] = 20;
    233. name["Gyarados"] = 21;
    234. name["Vaporeon"] = 22;
    235. name["Relicanth"] = 23;
    236. name["Regice"] = 24;
    237. name["Kyurem-EX"] = 25;
    238. name["Jolteon"] = 26;
    239. name["Ampharos-EX"] = 27;
    240. name["M Ampharos-EX"] = 28;
    241. name["Rotom"] = 29;
    242. name["Unown"] = 30;
    243. name["Baltoy"] = 31;
    244. name["Baltoy"] = 32;
    245. name["Claydol"] = 33;
    246. name["Golett"] = 34;
    247. name["Golurk"] = 35;
    248. name["Hoopa-EX"] = 36;
    249. name["Machamp-EX"] = 37;
    250. name["Wooper"] = 38;
    251. name["Quagsire"] = 39;
    252. name["Regirock"] = 40;
    253. name["Golurk"] = 41;
    254. name["Tyranitar-EX"] = 42;
    255. name["M Tyranitar-EX"] = 43;
    256. name["Sableye"] = 44;
    257. name["Inkay"] = 45;
    258. name["Malamar"] = 46;
    259. name["Beldum"] = 47;
    260. name["Metang"] = 48;
    261. name["Metagross"] = 49;
    262. name["Metagross"] = 50;
    263. name["Registeel"] = 51;
    264. name["Ralts"] = 52;
    265. name["Kirlia"] = 53;
    266. name["Gardevoir"] = 54;
    267. name["Cottonee"] = 55;
    268. name["Whimsicott"] = 56;
    269. name["Giratina-EX"] = 57;
    270. name["Goomy"] = 58;
    271. name["Sliggoo"] = 59;
    272. name["Goodra"] = 60;
    273. name["Meowth"] = 61;
    274. name["Persian"] = 62;
    275. name["Eevee"] = 63;
    276. name["Porygon"] = 64;
    277. name["Porygon2"] = 65;
    278. name["Porygon-Z"] = 66;
    279. name["Porygon-Z"] = 67;
    280. name["Lugia-EX"] = 68;
    281. name["Ace Trainer"] = 69;
    282. name["Ampharos Spirit Link"] = 70;
    283. name["Eco Arm"] = 71;
    284. name["Energy Recycler"] = 72;
    285. name["Faded Town"] = 73;
    286. name["Forest of Giant Plants"] = 74;
    287. name["Hex Maniac"] = 75;
    288. name["Level Ball"] = 76;
    289. name["Lucky Helmet"] = 77;
    290. name["Lysandre"] = 78;
    291. name["Paint Roller"] = 79;
    292. name["Sceptile Spirit Link"] = 80;
    293. name["Tyranitar Spirit Link"] = 81;
    294. name["Dangerous Energy"] = 82;
    295. name["Flash Energy"] = 83;
    296. name["Sceptile-EX"] = 84;
    297. name["M Sceptile-EX"] = 85;
    298. name["Kyurem-EX"] = 86;
    299. name["Ampharos-EX"] = 87;
    300. name["M Ampharos-EX"] = 88;
    301. name["Hoopa-EX"] = 89;
    302. name["Machamp-EX"] = 90;
    303. name["Tyranitar-EX"] = 91;
    304. name["M Tyranitar-EX"] = 92;
    305. name["Giratina-EX"] = 93;
    306. name["Lugia-EX"] = 94;
    307. name["Steven"] = 95;
    308. name["Primal Kyogre-EX"] = 96;
    309. name["Primal Groudon-EX"] = 97;
    310. name["M Rayquaza-EX"] = 98;
    311. name["Energy Retrieval"] = 99;
    312. name["Trainers' Mail"] = 100;
    313. return name;
    314. }
    315.  
    316.  
    317. // Destructor
    318. Album::~Album()
    319. {
    320.  
    321. }
    To copy to clipboard, switch view to plain text mode 

    Qt Code:
    1. // AlbumCardsModel.h
    2. class AlbumCardsModel : public AbstractCardModel
    3. {
    4. Q_OBJECT
    5. public:
    6. enum AlbumRoles { AlbumNameRole = Qt::UserRole + 1};
    7. AlbumCardsModel(AlbumsManager *newAlbumsManager, CardsManager *newCardsManager, QObject *parent = 0);
    8. void showAlbum(const QString &albumId);
    9. int rowCount(const QModelIndex &parent) const;
    10.  
    11. protected:
    12. Card cardForIndex(const QModelIndex &index) const;
    13.  
    14. private slots:
    15. // gets connected to m_albumManager's albumRemoved() signal
    16. void onAlbumRemoved(const QString &albumId);
    17. void onCardAdded(const QString &albumId, const QString cardId);
    18. void onCardRemoved(const QString &albumId, const QString cardId);
    19.  
    20. private:
    21. AlbumsManager *m_albumsManager;
    22. Album m_album;
    23. };
    To copy to clipboard, switch view to plain text mode 

    Qt Code:
    1. // AlbumCardsModel.cpp
    2. #include "albumcardsmodel.h"
    3.  
    4. AlbumCardsModel::AlbumCardsModel(AlbumsManager *newAlbumsManager, CardsManager *newCardsManager, QObject *parent)/*: QObject(parent)*/
    5. {
    6. this->m_albumsManager = newAlbumsManager;
    7. this->m_cardsManager = newCardsManager;
    8. }
    9.  
    10.  
    11. void AlbumCardsModel::showAlbum(const QString &albumId)
    12. {
    13. beginResetModel();
    14. m_album = m_albumsManager->album(albumId);
    15. endResetModel();
    16. }
    17.  
    18. int AlbumCardsModel::rowCount(const QModelIndex&) const
    19. {
    20. return m_album.getNrOfCards();
    21. }
    22.  
    23. Card AlbumCardsModel::cardForIndex(const QModelIndex &index) const
    24. {
    25. return m_cardManager->card(m_album.cardIDs.at(index.row()));
    26. }
    27.  
    28. void AlbumCardsModel::onAlbumRemoved(const QString &albumId)
    29. {
    30. if (albumId != m_album.getAlbumId()) return;
    31.  
    32. beginResetModel();
    33. m_album = Album();
    34. endResetModel();
    35. }
    36.  
    37. void AlbumCardsModel::onCardAdded(const QString &albumId, const QString &cardId)
    38. {
    39. // if (albumId != m_album.getAlbumId()) return;
    40.  
    41. // const Album updatedAlbum = m_albumManager->album(albumId);
    42. // const int row = updatedAlbum.cardIDs.indexOf(cardId);
    43.  
    44. // beginInsertRows(QModelIndex(), row, row);
    45.  
    46. // this->m_album = updatedAlbum;
    47.  
    48. // endInsertRows();
    49. }
    50.  
    51. void AlbumCardsModel::onCardRemoved(const QString &albumId, const QString &cardId)
    52. {
    53. // if (albumId != m_album.getAlbumId()) return;
    54.  
    55. // const Album updatedAlbum = m_albumManager->album(albumId);
    56. // const int row = m_album.cardIDs.indexOf(cardId);
    57.  
    58. // beginRemoveRows(QModelIndex(), row, row);
    59.  
    60. // m_album = updatedAlbum;
    61.  
    62. // endRemoveRows();
    63. }
    To copy to clipboard, switch view to plain text mode 

    Qt Code:
    1. // AlbumsManager.h
    2.  
    3. class Card;
    4. class AlbumsManager : public QObject
    5. {
    6. Q_OBJECT
    7. public:
    8. // Default Constructor
    9. AlbumsManager(QObject* parent = 0);
    10.  
    11. Album createAlbum(const QString &name);
    12.  
    13. Album album(const QString &id) const;
    14. QList<Album> albums() const;
    15.  
    16. int count() const;
    17.  
    18. void addAlbum(const Album& source);
    19. void removeAlbum(const int index);
    20.  
    21. void addCard(const QString &albumId, const QString &cardId);
    22. void removeCard(const QString &albumId, const QString &cardId);
    23.  
    24. signals:
    25. void albumAdded(const QString &id);
    26. void albumRemoved(const QString &id);
    27.  
    28. void cardAdded(const QString &albumId, const QStringList &cardIDs);
    29. void cardRemoved(const QString &albumId, const QStringList &cardIDs);
    30.  
    31. private:
    32. QList<Album> m_albums;
    33. };
    To copy to clipboard, switch view to plain text mode 

    Qt Code:
    1. // AlbumsManager.cpp
    2. #include "albumsmanager.h"
    3.  
    4. AlbumsManager::AlbumsManager(QObject *parent): QObject(parent)
    5. {
    6.  
    7. }
    8.  
    9.  
    10. Album AlbumsManager::createAlbum(const QString &name)
    11. {
    12. Album* alb = new Album(name);
    13. return *alb;
    14. }
    15.  
    16. // CARDS IN ALBUM
    17. void AlbumsManager::addAlbum(const Album& source)
    18. {
    19. m_albums.append(source);
    20. }
    21.  
    22. void AlbumsManager::removeAlbum(const int index)
    23. {
    24. m_albums.removeAt(index);
    25. }
    26.  
    27. Album AlbumsManager::album(const QString &id) const
    28. {
    29. bool albumFound = false;
    30. int albumMatch;
    31. for(int i = 0; i < this->count(); i++)
    32. {
    33. if(m_albums[i].getAlbumId() == id)
    34. {
    35. albumFound = true;
    36. albumMatch = i;
    37. }
    38. }
    39.  
    40. if(albumFound == true)
    41. {
    42. return this->m_albums[albumMatch];
    43. }
    44. else
    45. {
    46. return Album();
    47. }
    48. }
    49.  
    50.  
    51. QList<Album> AlbumsManager::albums() const
    52. {
    53. return this->m_albums;
    54. }
    55.  
    56.  
    57. int AlbumsManager::count() const
    58. {
    59. return this->m_albums.count();
    60. }
    61.  
    62.  
    63. void AlbumsManager::addCard(const QString &albumId, const QString &cardId)
    64. {
    65. bool albumFound = false;
    66. int albumMatch;
    67. for(int i = 0; i < this->count(); i++)
    68. {
    69. if(m_albums[i].getAlbumId() == albumId)
    70. {
    71. albumFound = true;
    72. albumMatch = i;
    73. }
    74. }
    75.  
    76. if(albumFound == true)
    77. {
    78. this->m_albums[albumMatch].addCardById(cardId);
    79. }
    80. }
    81.  
    82. void AlbumsManager::removeCard(const QString &albumId, const QString &cardId)
    83. {
    84.  
    85. }
    To copy to clipboard, switch view to plain text mode 

    Qt Code:
    1. // App.h
    2. class App
    3. {
    4. Q_OBJECT
    5.  
    6. public:
    7. // Roles
    8. enum AlbumRoles { albumNameRole = Qt::UserRole + 1 };
    9.  
    10. // Constructor
    11. explicit App(QObject *parent = 0);
    12.  
    13. // Destructor
    14. ~App();
    15.  
    16. // Append
    17. void addAlbum(const Album &album);
    18.  
    19. // Position
    20. int rowCount(const QModelIndex & parent = QModelIndex()) const;
    21.  
    22. // Data from child items
    23. QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;
    24.  
    25. protected:
    26. // Role names
    27. QHash<int, QByteArray> roleNames() const;
    28.  
    29. private:
    30. // Children
    31. QList<Album> m_albums;
    32. };
    To copy to clipboard, switch view to plain text mode 

    Qt Code:
    1. // App.cpp
    2. #include "app.h"
    3.  
    4. App::App(QObject *parent)/*: QObject(parent)*/
    5. {
    6.  
    7. }
    8.  
    9. // Append
    10. void App::addAlbum(const Album &album)
    11. {
    12. m_albums.append(album);
    13. }
    14.  
    15. // Position
    16. int App::rowCount(const QModelIndex & parent) const {
    17. Q_UNUSED(parent);
    18. return m_albums.count();
    19. }
    20.  
    21. // Data
    22. QVariant App::data(const QModelIndex & index, int role) const {
    23. if (index.row() < 0 || index.row() >= m_albums.count())
    24. return QVariant();
    25.  
    26. const Album &album = m_albums[index.row()];
    27. if (role == albumNameRole)
    28. return album.getAlbumName();
    29. return QVariant();
    30. }
    31.  
    32. QHash<int, QByteArray> App::roleNames() const {
    33. QHash<int, QByteArray> roles;
    34. roles[albumNameRole] = "name";
    35. return roles;
    36. }
    To copy to clipboard, switch view to plain text mode 


    Qt Code:
    1. // Card.h
    2. class Card
    3. {
    4. private:
    5. QString cardID;
    6. QString name;
    7. QString imageURL;
    8. QString subtype;
    9. QString supertype;
    10. int number;
    11. QString artist;
    12. QString rarity;
    13. QString series;
    14. QString set;
    15. QString setCode;
    16. QString condition;
    17. QString status;
    18.  
    19. public:
    20. // Default Constructor
    21. Card();
    22.  
    23. // Overloaded Constructor
    24. Card(const QString &cardID, const QString &name, const QString &imageURL, const QString &subtype, const QString &supertype, const int &number, const QString &artist, const QString &rarity, const QString &series, const QString &set, const QString &setCode, const QString &condition, const QString &status);
    25.  
    26. // Copy Constructor
    27. Card(const Card& source);
    28.  
    29. // Assignment Opperator
    30. Card& operator=(const Card& source);
    31.  
    32. // GETTERS
    33. QString getCardID() const;
    34. QString getName() const;
    35. QString getImageURL() const;
    36. QString getSubtype() const;
    37. QString getSupertype() const;
    38. int getNumber() const;
    39. QString getArtist() const;
    40. QString getRarity() const;
    41. QString getSeries() const;
    42. QString getSet() const;
    43. QString getSetCode() const;
    44. QString getCondition() const;
    45. QString getStatus() const;
    46.  
    47.  
    48. // SETTERS
    49. void setCardID(const QString newCardID);
    50. void setName(const QString newName);
    51. void setImageURL(const QString newImageURL);
    52. void setSubtype(const QString newSubtype);
    53. void setSupertype(const QString newSupertype);
    54. void setNumber(const int newNumber);
    55. void setArtist(const QString newArtist);
    56. void setRarity(const QString newRarity);
    57. void setSeries(const QString newSeries);
    58. void setSet(const QString newSet);
    59. void setSetCode(const QString newSetCode);
    60. void setCondition(const QString newCondition);
    61. void setStatus(const QString newStatus);
    62.  
    63. // Destructor
    64. ~Card();
    65. };
    To copy to clipboard, switch view to plain text mode 

    Qt Code:
    1. // Card.cpp
    2. #include "card.h"
    3.  
    4. // Default Constructor
    5. Card::Card()
    6. {
    7. this->cardID = "Default Card ID";
    8. this->name = "Default Card Name";
    9. this->imageURL = "Default Card Image URL";
    10. this->subtype = "Default Card Subtype";
    11. this->supertype = "Default Card Supertype";
    12. this->number = 1;
    13. this->artist = "Default Card Artist";
    14. this->rarity = "Default Card Rarity";
    15. this->series = "Default Card Series";
    16. this->set = "Default Card Set";
    17. this->setCode = "Default Card Set Code";
    18. this->condition = "Default Card Condition";
    19. this->status = "Default Card Status";
    20. }
    21.  
    22. // Overloaded Constructor
    23. Card::Card(const QString &newCardID, const QString &newName, const QString &newImageURL, const QString &newSubtype, const QString &newSupertype, const int &newNumber, const QString &newArtist, const QString &newRarity, const QString &newSeries, const QString &newSet, const QString &newSetCode, const QString &newCondition, const QString &newStatus)
    24. {
    25. this->cardID = newCardID;
    26. this->name = newName;
    27. this->imageURL = newImageURL;
    28. this->subtype = newSubtype;
    29. this->supertype = newSupertype;
    30. this->number = newNumber;
    31. this->artist = newArtist;
    32. this->rarity = newRarity;
    33. this->series = newSeries;
    34. this->set = newSet;
    35. this->setCode = newSetCode;
    36. this->condition = newCondition;
    37. this->status = newStatus;
    38. }
    39.  
    40. // Copy Constructor
    41. Card::Card(const Card& source)
    42. {
    43. this->cardID = source.cardID;
    44. this->name = source.name;
    45. this->imageURL = source.imageURL;
    46. this->subtype = source.subtype;
    47. this->supertype = source.supertype;
    48. this->number = source.number;
    49. this->artist = source.artist;
    50. this->rarity = source.artist;
    51. this->series = source.series;
    52. this->set = source.set;
    53. this->setCode = source.setCode;
    54. this->condition = source.condition;
    55. this->status = source.status;
    56. }
    57.  
    58. // Assignment Opperator
    59. Card& Card::operator=(const Card& source)
    60. {
    61. if(this != &source)
    62. {
    63. this->cardID = source.cardID;
    64. this->name = source.name;
    65. this->imageURL = source.imageURL;
    66. this->subtype = source.subtype;
    67. this->supertype = source.supertype;
    68. this->number = source.number;
    69. this->artist = source.artist;
    70. this->rarity = source.artist;
    71. this->series = source.series;
    72. this->set = source.set;
    73. this->setCode = source.setCode;
    74. this->condition = source.condition;
    75. this->status = source.status;
    76. }
    77. return *this;
    78. }
    79.  
    80. // GETTERS
    81. QString Card::getCardID() const
    82. {
    83. return this->cardID;
    84. }
    85.  
    86. QString Card::getName() const
    87. {
    88. return this->name;
    89. }
    90.  
    91. QString Card::getImageURL() const
    92. {
    93. return this->imageURL;
    94. }
    95.  
    96. QString Card::getSubtype() const
    97. {
    98. return this->subtype;
    99. }
    100.  
    101. QString Card::getSupertype() const
    102. {
    103. return this->supertype;
    104. }
    105.  
    106. int Card::getNumber() const
    107. {
    108. return this->number;
    109. }
    110.  
    111. QString Card::getArtist() const
    112. {
    113. return this->artist;
    114. }
    115.  
    116. QString Card::getRarity() const
    117. {
    118. return this->rarity;
    119. }
    120.  
    121. QString Card::getSeries() const
    122. {
    123. return this->series;
    124. }
    125.  
    126. QString Card::getSet() const
    127. {
    128. return this->set;
    129. }
    130.  
    131. QString Card::getSetCode() const
    132. {
    133. return this->setCode;
    134. }
    135.  
    136. QString Card::getCondition() const
    137. {
    138. return this->condition;
    139. }
    140.  
    141. QString Card::getStatus() const
    142. {
    143. return this->status;
    144. }
    145.  
    146. // SETTERS
    147. void Card::setCardID(const QString newCardID)
    148. {
    149. this->cardID = newCardID;
    150. }
    151.  
    152. void Card::setName(const QString newName)
    153. {
    154. this->name = newName;
    155. }
    156.  
    157. void Card::setImageURL(const QString newImageURL)
    158. {
    159. this->imageURL = newImageURL;
    160. }
    161.  
    162. void Card::setSubtype(const QString newSubtype)
    163. {
    164. this->subtype = newSubtype;
    165. }
    166.  
    167. void Card::setSupertype(const QString newSupertype)
    168. {
    169. this->supertype = newSupertype;
    170. }
    171.  
    172. void Card::setNumber(const int newNumber)
    173. {
    174. this->number = newNumber;
    175. }
    176.  
    177. void Card::setArtist(const QString newArtist)
    178. {
    179. this->artist = newArtist;
    180. }
    181.  
    182. void Card::setRarity(const QString newRarity)
    183. {
    184. this->rarity = newRarity;
    185. }
    186.  
    187. void Card::setSeries(const QString newSeries)
    188. {
    189. this->series = newSeries;
    190. }
    191.  
    192. void Card::setSet(const QString newSet)
    193. {
    194. this->set = newSet;
    195. }
    196.  
    197. void Card::setSetCode(const QString newSetCode)
    198. {
    199. this->setCode = newSetCode;
    200. }
    201.  
    202. void Card::setCondition(const QString newCondition)
    203. {
    204. this->condition = newCondition;
    205. }
    206.  
    207. void Card::setStatus(const QString newStatus)
    208. {
    209. this->status = newStatus;
    210. }
    211.  
    212. // Destructor
    213. Card::~Card()
    214. {
    215.  
    216. }
    To copy to clipboard, switch view to plain text mode 

    Qt Code:
    1. // CardsManager.h
    2. class CardsManager : public QObject
    3. {
    4. Q_OBJECT
    5.  
    6. public:
    7. // returns an invalid card if ID is not found, e.g. Card object with empty "id"
    8. Card addCardById(const QString &id);
    9. Card addCardByName(const QString &newName);
    10.  
    11. Card card(const QString &id) const;
    12. QList<Card> cards() const;
    13.  
    14. int count() const;
    15.  
    16. signals:
    17. void cardAdded(const QString &id);
    18. void cardRemoved(const QString &id);
    19.  
    20. protected:
    21. QHash<QString, int> nameToId() const;
    22.  
    23. private:
    24. QList<Card> m_cards;
    25. };
    To copy to clipboard, switch view to plain text mode 

    Qt Code:
    1. // CardsManager.cpp
    2. #include "cardsmanager.h"
    3.  
    4. Card CardsManager::addCardById(const QString &id)
    5. {
    6. // Card info
    7. int number;
    8. QString nrString;
    9. QString name;
    10. QString cardId;
    11. QString subtype;
    12. QString supertype;
    13. QString artist;
    14. QString rarity;
    15. QString series;
    16. QString set;
    17. QString setCode;
    18. QString imageUrl;
    19. QString status;
    20. QString condition;
    21.  
    22. // Build file name
    23. QString fileName = ":/cards/Resources/JSON/xy7-";
    24. fileName.append(id);
    25. fileName.append(".json");
    26.  
    27. // Open file
    28. QFile file(fileName);
    29. if(!file.open(QFile::ReadOnly | QFile::Text))
    30. {
    31. qDebug() << "Error: Could not open file for reading";
    32. return Card();
    33. }
    34.  
    35. // Save file information in fileText
    36. QTextStream in(&file);
    37. QString fileText = in.readAll();
    38.  
    39. // Close file
    40. file.close();
    41.  
    42. // Create card jsonObject from fileText
    43. QJsonDocument jsonDocument = QJsonDocument::fromJson(fileText.toUtf8());
    44. QJsonObject rootObject = jsonDocument.object();
    45. QJsonValue value = rootObject.value(QString("card"));
    46. QJsonObject cardRootValues = value.toObject();
    47.  
    48. // Set values for card variables
    49. name = cardRootValues.value("name").toString();
    50. cardId = cardRootValues.value("id").toString();
    51. subtype = cardRootValues.value("subtype").toString();
    52. supertype = cardRootValues.value("supertype").toString();
    53. nrString = cardRootValues.value("number").toString();
    54. number = nrString.toInt();
    55. artist = cardRootValues.value("artist").toString();
    56. rarity = cardRootValues.value("rarity").toString();
    57. series = cardRootValues.value("series").toString();
    58. set = cardRootValues.value("set").toString();
    59. setCode = cardRootValues.value("setCode").toString();
    60. imageUrl = cardRootValues.value("imageURL").toString();
    61.  
    62. // Create Card instance from variables
    63. Card* crdPntr = nullptr;
    64. crdPntr = new Card(cardId, name, imageUrl, subtype, supertype, number, artist, rarity, series, set, setCode, condition, status);
    65.  
    66. return *crdPntr;
    67. }
    68.  
    69. Card CardsManager::addCardByName(const QString &newName)
    70. {
    71. // Card info
    72. int number;
    73. QString nrString;
    74. QString name;
    75. QString cardId;
    76. QString subtype;
    77. QString supertype;
    78. QString artist;
    79. QString rarity;
    80. QString series;
    81. QString set;
    82. QString setCode;
    83. QString imageUrl;
    84. QString status;
    85. QString condition;
    86.  
    87. // Build file name
    88. QString fileName = ":/cards/Resources/JSON/xy7-";
    89. QString id = nameToId().value(newName);
    90. fileName.append(id);
    91. fileName.append(".json");
    92.  
    93. // Open file
    94. QFile file(fileName);
    95. if(!file.open(QFile::ReadOnly | QFile::Text))
    96. {
    97. qDebug() << "Error: Could not open file for reading";
    98. return Card();
    99. }
    100.  
    101. // Save file information in fileText
    102. QTextStream in(&file);
    103. QString fileText = in.readAll();
    104.  
    105. // Close file
    106. file.close();
    107.  
    108. // Create card jsonObject from fileText
    109. QJsonDocument jsonDocument = QJsonDocument::fromJson(fileText.toUtf8());
    110. QJsonObject rootObject = jsonDocument.object();
    111. QJsonValue value = rootObject.value(QString("card"));
    112. QJsonObject cardRootValues = value.toObject();
    113.  
    114. // Set values for card variables
    115. name = cardRootValues.value("name").toString();
    116. cardId = cardRootValues.value("id").toString();
    117. subtype = cardRootValues.value("subtype").toString();
    118. supertype = cardRootValues.value("supertype").toString();
    119. nrString = cardRootValues.value("number").toString();
    120. number = nrString.toInt();
    121. artist = cardRootValues.value("artist").toString();
    122. rarity = cardRootValues.value("rarity").toString();
    123. series = cardRootValues.value("series").toString();
    124. set = cardRootValues.value("set").toString();
    125. setCode = cardRootValues.value("setCode").toString();
    126. imageUrl = cardRootValues.value("imageURL").toString();
    127.  
    128. // Create Card instance from variables
    129. Card* crdPntr = nullptr;
    130. crdPntr = new Card(cardId, name, imageUrl, subtype, supertype, number, artist, rarity, series, set, setCode, condition, status);
    131.  
    132. return *crdPntr;
    133. }
    134.  
    135. Card CardsManager::card(const QString &id) const
    136. {
    137. return Card(id,"Gloom","http://s3.amazonaws.com/pokemontcg/xy7/2.png","Stage 1","Pokémon",2,"Masakazu Fukuda","Uncommon","XY","Ancient Origins","xy7","Mint","In my collection");
    138.  
    139. }
    140.  
    141. QList<Card> CardsManager::cards() const
    142. {
    143. return m_cards;
    144. }
    145.  
    146. int CardsManager::count() const
    147. {
    148. return this->m_cards.count();
    149. }
    150.  
    151. QHash<QString, int> CardsManager::nameToId() const {
    152. QHash<QString, int> name;
    153. name["Oddish"] = 1;
    154. name["Gloom"] = 2;
    155. name["Vileplume"] = 3;
    156. name["Bellossom"] = 4;
    157. name["Spinarak"] = 5;
    158. name["Ariados"] = 6;
    159. name["Sceptile-EX"] = 7;
    160. name["M Sceptile-EX"] = 8;
    161. name["Combee"] = 9;
    162. name["Vespiquen"] = 10;
    163. name["Vespiquen"] = 11;
    164. name["Virizion"] = 12;
    165. name["Flareon"] = 13;
    166. name["Entei"] = 14;
    167. name["Entei"] = 15;
    168. name["Larvesta"] = 16;
    169. name["Volcarona"] = 17;
    170. name["Volcarona"] = 18;
    171. name["Magikarp"] = 19;
    172. name["Gyarados"] = 20;
    173. name["Gyarados"] = 21;
    174. name["Vaporeon"] = 22;
    175. name["Relicanth"] = 23;
    176. name["Regice"] = 24;
    177. name["Kyurem-EX"] = 25;
    178. name["Jolteon"] = 26;
    179. name["Ampharos-EX"] = 27;
    180. name["M Ampharos-EX"] = 28;
    181. name["Rotom"] = 29;
    182. name["Unown"] = 30;
    183. name["Baltoy"] = 31;
    184. name["Baltoy"] = 32;
    185. name["Claydol"] = 33;
    186. name["Golett"] = 34;
    187. name["Golurk"] = 35;
    188. name["Hoopa-EX"] = 36;
    189. name["Machamp-EX"] = 37;
    190. name["Wooper"] = 38;
    191. name["Quagsire"] = 39;
    192. name["Regirock"] = 40;
    193. name["Golurk"] = 41;
    194. name["Tyranitar-EX"] = 42;
    195. name["M Tyranitar-EX"] = 43;
    196. name["Sableye"] = 44;
    197. name["Inkay"] = 45;
    198. name["Malamar"] = 46;
    199. name["Beldum"] = 47;
    200. name["Metang"] = 48;
    201. name["Metagross"] = 49;
    202. name["Metagross"] = 50;
    203. name["Registeel"] = 51;
    204. name["Ralts"] = 52;
    205. name["Kirlia"] = 53;
    206. name["Gardevoir"] = 54;
    207. name["Cottonee"] = 55;
    208. name["Whimsicott"] = 56;
    209. name["Giratina-EX"] = 57;
    210. name["Goomy"] = 58;
    211. name["Sliggoo"] = 59;
    212. name["Goodra"] = 60;
    213. name["Meowth"] = 61;
    214. name["Persian"] = 62;
    215. name["Eevee"] = 63;
    216. name["Porygon"] = 64;
    217. name["Porygon2"] = 65;
    218. name["Porygon-Z"] = 66;
    219. name["Porygon-Z"] = 67;
    220. name["Lugia-EX"] = 68;
    221. name["Ace Trainer"] = 69;
    222. name["Ampharos Spirit Link"] = 70;
    223. name["Eco Arm"] = 71;
    224. name["Energy Recycler"] = 72;
    225. name["Faded Town"] = 73;
    226. name["Forest of Giant Plants"] = 74;
    227. name["Hex Maniac"] = 75;
    228. name["Level Ball"] = 76;
    229. name["Lucky Helmet"] = 77;
    230. name["Lysandre"] = 78;
    231. name["Paint Roller"] = 79;
    232. name["Sceptile Spirit Link"] = 80;
    233. name["Tyranitar Spirit Link"] = 81;
    234. name["Dangerous Energy"] = 82;
    235. name["Flash Energy"] = 83;
    236. name["Sceptile-EX"] = 84;
    237. name["M Sceptile-EX"] = 85;
    238. name["Kyurem-EX"] = 86;
    239. name["Ampharos-EX"] = 87;
    240. name["M Ampharos-EX"] = 88;
    241. name["Hoopa-EX"] = 89;
    242. name["Machamp-EX"] = 90;
    243. name["Tyranitar-EX"] = 91;
    244. name["M Tyranitar-EX"] = 92;
    245. name["Giratina-EX"] = 93;
    246. name["Lugia-EX"] = 94;
    247. name["Steven"] = 95;
    248. name["Primal Kyogre-EX"] = 96;
    249. name["Primal Groudon-EX"] = 97;
    250. name["M Rayquaza-EX"] = 98;
    251. name["Energy Retrieval"] = 99;
    252. name["Trainers' Mail"] = 100;
    253. return name;
    254. }
    To copy to clipboard, switch view to plain text mode 


    Added after 7 minutes:


    Maybe I shouldn't have dumped all that code. Either way, here is how the UI looks like for now:
    https://streamable.com/1k11j

    Thanks again for all the help!


    Added after 5 minutes:


    Last edited by Nizars; 31st December 2016 at 02:42.

  14. #10
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    4,721
    Thanks
    259
    Thanked 760 Times in 750 Posts
    Qt products
    Qt5
    Platforms
    Windows Android

    Default Re: Integration: Nested Tree Parent Child C++ Classes with Models/Delegates for QML

    Looks nice. There are some refinements I'd make to the code, but otherwise it looks good and I don't see any obvious errors.

    Edit - one error: Album:: operator=() needs to clear the existing list of cards before assigning the new list of cards. You can do this by simply writing "thisList = newList;" - you don't need to iterate over the incoming list of cards and add them one by one with a copy constructor. The list assignment operator will do all that. You've already assigned "nrOfCards" in the previous line, so going through addCard for each card you are copying is just extra work for nothing. Since you are always setting nrOfCards to card.count(), why even bother with this variable? It's something that could get out of sync if you forget to update it in some place where you change the card list. Just return card.count() whenever you need the number of cards.
    Last edited by d_stranz; 31st December 2016 at 03:00.
    <=== The Great Pumpkin says ===>
    Please use CODE tags when posting source code so it is more readable. Click "Go Advanced" and then the "#" icon to insert the tags. Paste your code between them.

  15. The following user says thank you to d_stranz for this useful post:

    Nizars (31st December 2016)

  16. #11
    Join Date
    Dec 2016
    Posts
    46
    Thanks
    20
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Integration: Nested Tree Parent Child C++ Classes with Models/Delegates for QML

    Thank you Stanz!

  17. #12
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,419
    Thanks
    37
    Thanked 1,546 Times in 1,496 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Integration: Nested Tree Parent Child C++ Classes with Models/Delegates for QML

    Quote Originally Posted by Nizars View Post
    What is the role of a <class>Manager class? I am just trying to understand how it fits in.
    One reason is to separate data from handling the data, i.e. the Card and Album class are only concerned about their data, not about anything else.

    The main reason, however, is to provide the necessary change notification on operations that add/remove/change data.
    This is the part from one of my earlier comments about "keeping the needs of the UI in mind". I.e. a model will need to be get notification somehow that cards have been added or albums have changed.

    That requires an "active" object, e.g. something having signals and we don't want these in the data classes.
    So adding a card to an Album needs to go through the AlbumManager, otherwise you could end up with an Album that has cards the model does not know about.

    Quote Originally Posted by Nizars View Post
    Say I want to to add copy constractors and assignment opperators for the App, Album and Card classes, where would those be implemented? in their respective classes?
    Yes

    Quote Originally Posted by Nizars View Post
    What about the Setter and Getter class methods such as "QString getCardName() const;"? Same with the default and overloaded constructors? should I even have a default constructor in the original class?
    Yes, in the data classes.
    As d_stranz said, no need for copy constructor or assignment operator as the default implementation generated by the compiler will do nicely for such easy classes.

    Definitely have a default constructor, e.g. for use cases like this
    Qt Code:
    1. Card card;
    2. if (m_cardManager != 0) card = m_cardManager->card(someId);
    3. if (!card.isValid()) return;
    To copy to clipboard, switch view to plain text mode 

    Quote Originally Posted by Nizars View Post
    I have noticed that you combine each class and it's Manager class in the same document. Is there a reason or a benifit behind this practise? or is this simple down to preference and time saving?
    Just as a hint on how they go together.
    In a real project I would put each class declaration into a separate header.

    Quote Originally Posted by Nizars View Post
    I have created three different classes for each of the "core" classes. An Album class, an AlbumsManager class and an AlbumModel class. I am totally open to changing it to the template you wrote if it makes a difference.
    I think this is basically the setup I sketched, only with an additional helper class for Card models in case you want more than just "cards of one album".
    E.g. a AllCardsModel could also simply derive from AbstractCardsModel and would only need to provide rowCount() and cardForIndex()

    Cheers,
    _


    Added after 32 minutes:


    Quote Originally Posted by Nizars View Post
    For now, here is the code I've written so far in case you want to have a look at it. I don't expect any of you to go through it and make corrections, you have done more than enough. But if you want to point out something that I have misunderstood I would gladly have a look at it again.
    As d_stranz said, the "nrOfCards" in Album is questionable.
    It can't mean the number of cards inside the Album because it can be set individually and the number of cards is always m_cards.count().
    So what do you need it for?

    One other problematic thing is that you are creating instances of objects on the heap and then discard the pointer, leaking memory.
    E.g.
    Qt Code:
    1. Card* crdPntr = nullptr;
    2. crdPntr = new Card(cardId, name, imageUrl, subtype, supertype, number, artist, rarity, series, set, setCode, condition, status);
    3.  
    4. return *crdPntr;
    To copy to clipboard, switch view to plain text mode 
    The memory "crdPntr" points to won't be addressable after the return and will be lost until the program ends.
    There is no need here to create the Card instance on the hea

    Quote Originally Posted by Nizars View Post
    Qt Code:
    1. AbstractCardModel::AbstractCardModel(CardsManager *cardsManager, QObject *parent)/*: QObject(parent)*/
    To copy to clipboard, switch view to plain text mode 
    Pass the parent to the QAbstractListModel constructor

    Quote Originally Posted by Nizars View Post
    Qt Code:
    1. QVariant AbstractCardModel::data(const QModelIndex &index, int role) const
    2. {
    3. // if (index.row() < 0 || index.row() >= this->m_cards.count())
    4. // return QVariant();
    5.  
    6. const Card &card = cardForIndex(index);
    7. if (role == CardIDRole)
    8. return card.getCardID();
    9. else if (role == NameRole)
    To copy to clipboard, switch view to plain text mode 
    This would be more efficient with a "switch(role)"

    Quote Originally Posted by Nizars View Post
    Qt Code:
    1. // Album.h
    2. class Album
    3. {
    4. private:
    5. QList<Card> cards;
    To copy to clipboard, switch view to plain text mode 
    This is ok in your case because your Cards never change their content. If Cards would be changable your Album could easily end up with old copied of the Cards.
    Which is why I used just the list of IDs, so the cards would have to be fetched from the CardsManager when needed which should always have the latest version.

    But again, ok in your case since your cards never change.

    Quote Originally Posted by Nizars View Post
    Qt Code:
    1. QHash<QString, int> nameToId() const;
    To copy to clipboard, switch view to plain text mode 
    That seems to map card names to ids, so it is definitely in the wrong class.
    Album doesn't need to know that.

    Quote Originally Posted by Nizars View Post
    Qt Code:
    1. // CARDS IN ALBUM
    2. void addCard(const Card& source);
    3. void addCardById(const QString &id);
    4. void addCardByName(const QString &newName);
    To copy to clipboard, switch view to plain text mode 
    The last two are not in the correct class, they would create Card objects without the CardManager knowing about them.

    Quote Originally Posted by Nizars View Post
    Qt Code:
    1. Album::Album(/*QObject *parent*/)/*:QAbstractListModel(parent)*/
    2. {
    3. this->albumName = "Default Album Name";
    4. this->albumId = "DefaultAlbumID";
    To copy to clipboard, switch view to plain text mode 
    A default constructed Album should be invalid so that methods returning Album can indicate they haven't found the one they were asked for.
    Most easiest way to do that is to have all fields empty, especially the ID.

    Quote Originally Posted by Nizars View Post
    Qt Code:
    1. // Overloaded Constructor
    2. Album::Album(QString newAlbumName)
    3. {
    4. this->albumName = newAlbumName;
    5. this->albumId = "DefaultAlbumID";
    To copy to clipboard, switch view to plain text mode 
    That allows you to create two albums with different names and the same ID.
    IDs are usually unique, otherwise they become useless for lookup.

    Quote Originally Posted by Nizars View Post
    Qt Code:
    1. // AlbumCardsModel.cpp
    2. #include "albumcardsmodel.h"
    3.  
    4. AlbumCardsModel::AlbumCardsModel(AlbumsManager *newAlbumsManager, CardsManager *newCardsManager, QObject *parent)/*: QObject(parent)*/
    5. {
    6. this->m_albumsManager = newAlbumsManager;
    7. this->m_cardsManager = newCardsManager;
    8. }
    To copy to clipboard, switch view to plain text mode 
    This also needs to connect to the manager signals

    Quote Originally Posted by Nizars View Post
    Qt Code:
    1. void addCard(const QString &albumId, const QString &cardId);
    2. void removeCard(const QString &albumId, const QString &cardId);
    To copy to clipboard, switch view to plain text mode 
    Since you have Card objects in your Album you need to pass "Card" here as the second argument or pass a CardManager to the AlbumManager.
    Otherwise you will end up creating cards that the card manager knows nothing about.

    Cheers,
    _
    Last edited by anda_skoa; 31st December 2016 at 09:38.

  18. The following user says thank you to anda_skoa for this useful post:

    Nizars (31st December 2016)

  19. #13
    Join Date
    Dec 2016
    Posts
    46
    Thanks
    20
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Integration: Nested Tree Parent Child C++ Classes with Models/Delegates for QML

    I wish I can thank the both of you enough. I really appreciate all the help I have gotten from you. It really means a lot to me. I will go through everything again today but hopefully won't get glued to the screen all day today too, the gf will definitely not like that.

    Once again, I wish I can thank the both of you enough. Happy new year guys!

  20. #14
    Join Date
    Dec 2016
    Posts
    46
    Thanks
    20
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Integration: Nested Tree Parent Child C++ Classes with Models/Delegates for QML

    The only error that I can see right now is from:

    Qt Code:
    1. class AlbumCardsModel : public AbstractCardModel
    2. {
    3. Q_OBJECT
    4. public:
    5. //..
    6. AlbumCardsModel(AlbumsManager *newAlbumsManager, CardsManager *newCardsManager, QObject *parent = 0);
    7. //..
    8. private:
    9. AlbumsManager *m_albumsManager;
    10. Album m_album;
    11. };
    To copy to clipboard, switch view to plain text mode 

    Qt Code:
    1. AlbumCardsModel::AlbumCardsModel(AlbumsManager *newAlbumsManager, CardsManager *newCardsManager, QObject *parent)
    2. {
    3. this->m_albumsManager = newAlbumsManager;
    4. this->m_cardsManager = newCardsManager;
    5. }
    To copy to clipboard, switch view to plain text mode 

    Qt Code:
    1. albumcardsmodel.cpp:4: error: C2512: 'AbstractCardModel': no appropriate default constructor available
    To copy to clipboard, switch view to plain text mode 

    I am not really sure how to implement this constructor. If i pass :QObject(parent) it tells me that it is not a member or a base class. I am not sure whether I should pass the other two pointers somewhere else too.
    Same thing with your comment about connecting the signals. Not sure how to go about it but I will go through the wikis and documentations for those classes and try to understand the mechanisms at work here better.
    I think After this I will just have to register the types in main and set a couple of them as root context properties. I will experiment with that until I figure out the proper configuartion to go with.

  21. #15
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    4,721
    Thanks
    259
    Thanked 760 Times in 750 Posts
    Qt products
    Qt5
    Platforms
    Windows Android

    Default Re: Integration: Nested Tree Parent Child C++ Classes with Models/Delegates for QML

    In all of your constructors, you are ignoring the construction of the base class where there is one. So for example:

    Qt Code:
    1. // This:
    2.  
    3. AbstractCardModel::AbstractCardModel(CardsManager *cardsManager, QObject *parent)/*: QObject(parent)*/
    4. {
    5. this->m_cardsManager = cardsManager;
    6. }
    7.  
    8. // should be this:
    9.  
    10. AbstractCardModel::AbstractCardModel(CardsManager *cardsManager, QObject *parent)
    11. : QAbstractItemModel( parent )
    12. {
    13. this->m_cardsManager = cardsManager;
    14. }
    To copy to clipboard, switch view to plain text mode 

    albumcardsmodel.cpp:4: error: C2512: 'AbstractCardModel': no appropriate default constructor available
    This problem is the source of this compile error. Because you are not calling the base class constructor, C++ is trying to construct a default one. It can't because the only constructor it can find for AbstractCardModel takes two arguments, a pointer to a CardsManager and a QObject pointer to the parent. So change the constructor to read:

    Qt Code:
    1. AlbumCardsModel::AlbumCardsModel( AlbumsManager * albumsManager, CardsManager *cardsManager, QObject *parent)
    2. : AbstractCardModel( cardsManager, parent )
    3. //...
    To copy to clipboard, switch view to plain text mode 

    At run-time (especially for the models) this could cause problems because your classes would be created with default base class implementations as well as parentless (because you are not telling your base class who the parent is, so Qt never links it up).

    You should make sure that all of your constructors for QObject-derived classes (i.e. all of those that contain the Q_OBJECT macro) pass "parent" up to their base classes, and that all of those constructors have a "QObject * parent" argument, even if it defaults to "0".

    Note that Qt does not allow copy constructors or assignment operators for QObject-based classes.
    Last edited by d_stranz; 31st December 2016 at 17:36.
    <=== The Great Pumpkin says ===>
    Please use CODE tags when posting source code so it is more readable. Click "Go Advanced" and then the "#" icon to insert the tags. Paste your code between them.

  22. The following user says thank you to d_stranz for this useful post:

    Nizars (31st December 2016)

  23. #16
    Join Date
    Dec 2016
    Posts
    46
    Thanks
    20
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Integration: Nested Tree Parent Child C++ Classes with Models/Delegates for QML

    Hi guys, I hope you had a good new year's.

    I have learned a lot from the suggested methods and I am thankful for all your help.
    The classes are now complete and I am now integrating them through main.cpp.

    I have a few questions about this bit.
    Which classes do I register using: QmlRegisterType?
    I have registered the core classes App, Album & Card as well as AlbumsManager & CardsManager.
    When it comes the Models I have registered AlbumCardsModel. I didn't register AbstractCardsModel because it is a pure virtual class.

    I have also instaciated a CardsManager class, an AlbumsManager class and an AlbumCardsModel class which I provided pointers to the cardsManager and the albumsManager instances.
    All three have also been set as context properties.

    Through the QML side, I am able to create new Albums in albumsManager and add Cards to them but I am not able to get anything from AlbumCardsModel to show up. I believe that this is because of two things, the pointers I provided it's constructor in main.cpp gets deleted when the app starts or that I am unable to use it properly in the QML side. I get an error that the model: albumCardsModel in my ListView is undefined.

  24. #17
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,419
    Thanks
    37
    Thanked 1,546 Times in 1,496 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Integration: Nested Tree Parent Child C++ Classes with Models/Delegates for QML

    Quote Originally Posted by Nizars View Post
    Which classes do I register using: QmlRegisterType?
    Only those which you need to use as element types in QML.
    In your case most likely none.

    Quote Originally Posted by Nizars View Post
    I have also instaciated a CardsManager class, an AlbumsManager class and an AlbumCardsModel class which I provided pointers to the cardsManager and the albumsManager instances.
    All three have also been set as context properties.
    sounds good

    Quote Originally Posted by Nizars View Post
    Through the QML side, I am able to create new Albums in albumsManager and add Cards to them but I am not able to get anything from AlbumCardsModel to show up. I believe that this is because of two things, the pointers I provided it's constructor in main.cpp gets deleted when the app starts or that I am unable to use it properly in the QML side. I get an error that the model: albumCardsModel in my ListView is undefined.
    Hmm.
    Things you creating in the main() function are usually not deleted until the program ends.

    Did you do the setContextProperty() calls before loading the main QML file?
    Have you checked the "id" argument (first argument) with the id you are using on the QML side?

    Cheers,
    _

  25. #18
    Join Date
    Dec 2016
    Posts
    46
    Thanks
    20
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Integration: Nested Tree Parent Child C++ Classes with Models/Delegates for QML

    Thanks for your reply.
    You are right about not needed the Card and Album classes defined since I wouldn't be directly using them in the Front-end.

    I have been messing around with different configurations to diagnose the methods and understand what is going on when I instanciate objects. I will post the updated code below.

    AbstractCardsModel:

    Qt Code:
    1. #ifndef ABSTRACTCARDMODEL_H
    2. #define ABSTRACTCARDMODEL_H
    3. #include <QString>
    4. #include <QObject>
    5. #include <QAbstractListModel>
    6. #include "cardsmanager.h"
    7. #include "card.h"
    8.  
    9. class AbstractCardModel : public QAbstractListModel
    10. {
    11. Q_OBJECT
    12. public:
    13. // Card roles
    14. enum AlbumRoles { CardIDRole = Qt::UserRole + 1, NameRole, ImageURLRole, SubtypeRole, SupertypeRole, NumberRole, ArtistRole, RarityRole, SeriesRole, SetRole, SetCodeRole, ConditionRole, StatusRole};
    15.  
    16. // Default Constructor
    17. AbstractCardModel(QObject* parent = 0);
    18.  
    19. // Overloaded Constructor
    20. AbstractCardModel(CardsManager *cardsManager, QObject *parent = 0);
    21.  
    22. // Copy Constructor
    23. AbstractCardModel(const AbstractCardModel& source);
    24.  
    25. // Assignment Operator
    26. AbstractCardModel& operator=(const AbstractCardModel& source);
    27.  
    28. // this uses cardForIndex to get the card, then uses role to return the actual data
    29. QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
    30.  
    31. // Default Destructor
    32. ~AbstractCardModel();
    33.  
    34. protected:
    35. QHash<int, QByteArray> roleNames() const;
    36.  
    37. virtual Card cardForIndex(const QModelIndex &index) const = 0;
    38.  
    39. protected:
    40. CardsManager *m_cardsManager;
    41. };
    42.  
    43. #endif //ABSTRACTCARDMODEL_H
    To copy to clipboard, switch view to plain text mode 

    Qt Code:
    1. #include "abstractcardmodel.h"
    2.  
    3. // Default Constructor
    4. AbstractCardModel::AbstractCardModel(QObject* parent): QAbstractListModel(parent)
    5. {
    6. // For debugging purposes
    7. qDebug() << "[AbstractCardModel] [called] [Default constructor]";
    8. this->m_cardsManager = nullptr;
    9. }
    10.  
    11. // Overloaded Constructor
    12. AbstractCardModel::AbstractCardModel(CardsManager *cardsManager, QObject *parent): QAbstractListModel(parent)
    13. {
    14. // For debugging purposes
    15. qDebug() << "[AbstractCardModel] [called] [Overloaded constructor]";
    16. this->m_cardsManager = cardsManager;
    17. }
    18.  
    19. // Copy Constructor
    20. AbstractCardModel::AbstractCardModel(const AbstractCardModel& source)
    21. {
    22. qDebug() << "[AbstractCardModel] [called] [Copy Constructor]";
    23. this->m_cardsManager = source.m_cardsManager;
    24. }
    25.  
    26. // Assignment Operator
    27. AbstractCardModel& AbstractCardModel::operator=(const AbstractCardModel& source)
    28. {
    29. qDebug() << "[AbstractCardModel] [called] [Assignment Operator]";
    30. if(this != &source)
    31. {
    32. this->m_cardsManager = source.m_cardsManager;
    33. }
    34. return *this;
    35. }
    36.  
    37. QVariant AbstractCardModel::data(const QModelIndex &index, int role) const
    38. {
    39. // For debugging purposes
    40. qDebug() << "[AbstractCardModel] [called] >> data(const QModelIndex &index, int role)";
    41. if (index.row() < 0 || index.row() >= this->m_cardsManager->count())
    42. return QVariant();
    43.  
    44. const Card &card = cardForIndex(index);
    45. if (role == CardIDRole)
    46. return card.getCardID();
    47. else if (role == NameRole)
    48. return card.getName();
    49. else if (role == ImageURLRole)
    50. return card.getImageURL();
    51. else if (role == SubtypeRole)
    52. return card.getSubtype();
    53. else if (role == SupertypeRole)
    54. return card.getSupertype();
    55. else if (role == NumberRole)
    56. return card.getNumber();
    57. else if (role == ArtistRole)
    58. return card.getArtist();
    59. else if (role == RarityRole)
    60. return card.getRarity();
    61. else if (role == SeriesRole)
    62. return card.getSeries();
    63. else if (role == SetRole)
    64. return card.getSet();
    65. else if (role == SetCodeRole)
    66. return card.getSetCode();
    67. else if (role == ConditionRole)
    68. return card.getCondition();
    69. else if (role == StatusRole)
    70. return card.getStatus();
    71. return QVariant();
    72. }
    73.  
    74. // Role names
    75. QHash<int, QByteArray> AbstractCardModel::roleNames() const
    76. {
    77. // For debugging purposes
    78. qDebug() << "[AbstractCardModel] [called] >> roleNames()";
    79. QHash<int, QByteArray> roles;
    80. roles[CardIDRole] = "cardID";
    81. roles[NameRole] = "name";
    82. roles[ImageURLRole] = "imageURL";
    83. roles[SubtypeRole] = "subtype";
    84. roles[SupertypeRole] = "supertype";
    85. roles[NumberRole] = "number";
    86. roles[ArtistRole] = "artist";
    87. roles[RarityRole] = "rarity";
    88. roles[SeriesRole] = "series";
    89. roles[SetRole] = "set";
    90. roles[SetCodeRole] = "setCode";
    91. roles[ConditionRole] = "condition";
    92. roles[StatusRole] = "status";
    93. return roles;
    94. }
    95.  
    96. // Default Destructor
    97. AbstractCardModel::~AbstractCardModel()
    98. {
    99. // For debugging purposes
    100. qDebug() << "[AbstractCardModel] [called] [Default Destructor]";
    101. }
    To copy to clipboard, switch view to plain text mode 

    Album:

    Qt Code:
    1. #ifndef ALBUM_H
    2. #define ALBUM_H
    3. #include <QDebug>
    4. #include <QObject>
    5. #include <QString>
    6. #include <QVariant>
    7. #include <QList>
    8. #include <QAbstractListModel>
    9. #include <QQmlListProperty>
    10. #include <QModelIndex>
    11. #include "card.h"
    12.  
    13. class Album : public QObject
    14. {
    15. private:
    16. QStringList cardIDs; // Holds list of all the card IDs that are in the Album
    17. int albumId; // Holds a unique Album ID given to it from the AlbumsManager
    18. QString albumName; // Holds the user specified name for the Album
    19.  
    20. public:
    21. // Default Constructor
    22. Album(QObject* parent = 0);
    23.  
    24. // Overloaded Constructor
    25. Album(QString newAlbumName, int albumId, QObject* parent = 0);
    26.  
    27. // Copy Constructor
    28. Album(const Album& source);
    29.  
    30. // Assignment Operator
    31. Album& operator=(const Album& source);
    32.  
    33. // ALBUM GETTERS
    34. QString getAlbumName() const;
    35. int getAlbumId() const;
    36. int getNrOfCards() const;
    37.  
    38. // ALBUM SETTERS
    39. void setAlbumName(const QString newAlbumName);
    40. void setAlbumId(const int newAlbumId);
    41.  
    42. // CARDS IN ALBUM
    43. void addCard(const QString& cardID);
    44. void removeCard(const QString& cardID);
    45. QString getCardID(const int index);
    46. QStringList getCardIDs() const;
    47.  
    48. // Destructor
    49. ~Album();
    50. };
    51.  
    52. #endif // ALBUM_H
    To copy to clipboard, switch view to plain text mode 

    Qt Code:
    1. #include "album.h"
    2.  
    3. // Default Constructor
    4. Album::Album(QObject* parent): QObject(parent)
    5. {
    6. // For debugging purposes
    7. qDebug() << "[Album] [called] [albumId:" << albumId << "] [Default constructor]";
    8. }
    9.  
    10. // Overloaded Constructor
    11. Album::Album(QString newAlbumName, int albumId, QObject* parent): QObject(parent)
    12. {
    13. qDebug() << "[Album] [called] [albumId:" << albumId << "] [Overloaded constructor] || newAlbumName: " << newAlbumName << ", albumId: " << albumId;
    14. this->albumName = newAlbumName;
    15. this->albumId = albumId;
    16. }
    17.  
    18. // Copy Constructor
    19. Album::Album(const Album& source)
    20. {
    21. qDebug() << "[Album] [called] [albumId:" << albumId << "] [Copy constructor] || albumId: " << albumId;
    22. this->albumName = source.albumName;
    23. this->albumId = source.albumId;
    24. for(int i = 0; i < source.getNrOfCards(); i++)
    25. {
    26. this->addCard(source.cardIDs[i]);
    27. }
    28. }
    29.  
    30. // Assignment Operator
    31. Album& Album::operator =(const Album& source)
    32. {
    33. qDebug() << "[Album] [called] [albumId:" << albumId << "] [Assignment opperator] || albumId: " << albumId;
    34. if(this != &source)
    35. {
    36. this->albumName = source.albumName;
    37. this->albumId = source.albumId;
    38. for(int i = 0; i < source.getNrOfCards(); i++)
    39. {
    40. this->addCard(source.cardIDs[i]);
    41. }
    42. }
    43. return *this;
    44. }
    45.  
    46. // ALBUM GETTERS
    47. QString Album::getAlbumName() const
    48. {
    49. qDebug() << "[Album] [called] [albumId:" << albumId << "] >> getAlbumName() || returned: albumName: " << albumName;
    50. return albumName;
    51. }
    52.  
    53. int Album::getAlbumId() const
    54. {
    55. qDebug() << "[Album] [called] [albumId:" << albumId << "] >> getAlbumId() || returned: albumId: " << albumId;
    56. return albumId;
    57. }
    58.  
    59. int Album::getNrOfCards() const
    60. {
    61. qDebug() << "[Album] [called] [albumId:" << albumId << "] >> getNrOfCards() || returned count: " << cardIDs.count();
    62. return this->cardIDs.count();
    63. }
    64.  
    65. // ALBUM SETTERS
    66. void Album::setAlbumName(const QString newAlbumName)
    67. {
    68. qDebug() << "[Album] [albumId:" << albumId << "] [called] >> setAlbumName(const QString newAlbumName) || newAlbumName: " << newAlbumName;
    69. this->albumName = newAlbumName;
    70. }
    71.  
    72. void Album::setAlbumId(const int newAlbumId)
    73. {
    74. qDebug() << "[Album] [called] [albumId:" << albumId << "] >> setAlbumId(const int newAlbumId) || newAlbumId: " << newAlbumId;
    75. this->albumId = newAlbumId;
    76. }
    77.  
    78.  
    79. // CARDS IN ALBUM
    80. void Album::addCard(const QString& cardID)
    81. {
    82. qDebug() << "[Album] [called] [albumId:" << albumId << "] >> addCard(const QString& cardID): cardID: " << cardID;
    83. this->cardIDs.append(cardID);
    84. }
    85.  
    86. void Album::removeCard(const QString& cardID)
    87. {
    88. qDebug() << "[Album] [called] [albumId:" << albumId << "] >> removeCard(const QString& cardID): cardID: " << cardID;
    89. for(int i = 0; i < this->cardIDs.count(); i++)
    90. {
    91. if(cardIDs[i] == cardID)
    92. {
    93. qDebug() << "[Album] [update] [albumId:" << albumId << "] >> removeCard(const QString& cardID) || Card match found at i: " << i;
    94. this->cardIDs.removeAt(i);
    95. return;
    96. }
    97. }
    98. }
    99.  
    100.  
    101. QString/*&*/ Album::getCardID(const int index)
    102. {
    103. qDebug() << "[Album] [called] [albumId:" << albumId << "] >> getCardID(const int index) || index: " << index << ", Returning cardId: " << cardIDs[index];
    104. return this->cardIDs[index];
    105. }
    106.  
    107. QStringList Album::getCardIDs() const
    108. {
    109. qDebug() << "[Album] [called] [albumId:" << albumId << "] >> getCardIDs()";
    110. return this->cardIDs;
    111. }
    112.  
    113.  
    114. // Destructor
    115. Album::~Album()
    116. {
    117. qDebug() << "[Album] [called] [albumId:" << albumId << "] [Destructor]";
    118. }
    To copy to clipboard, switch view to plain text mode 

    AlbumCardsModel:

    Qt Code:
    1. #ifndef ALBUMCARDSMODEL_H
    2. #define ALBUMCARDSMODEL_H
    3. #include <QObject>
    4. #include <QString>
    5. #include <QVariant>
    6. #include <QDebug>
    7. #include <QList>
    8. #include <QAbstractListModel>
    9. #include <QQmlListProperty>
    10. #include <QModelIndex>
    11. #include "abstractcardmodel.h"
    12. #include "albumsmanager.h"
    13.  
    14.  
    15. class AlbumCardsModel : public AbstractCardModel
    16. {
    17. Q_OBJECT
    18. public:
    19. // Album name role
    20. enum AlbumRoles { AlbumNameRole = Qt::UserRole + 1};
    21.  
    22. // Default Constructor
    23. AlbumCardsModel(QObject *parent = 0);
    24.  
    25. AlbumCardsModel(AlbumsManager *albumsManager, CardsManager *cardsManager, QObject *parent = 0);
    26.  
    27. // Show a specific Album
    28. Q_INVOKABLE void showAlbum(const int &albumId);
    29.  
    30. // Get the
    31. int rowCount(const QModelIndex &parent) const;
    32.  
    33. protected:
    34. // Get the card object at the specified position in the Album
    35. Card cardForIndex(const QModelIndex &index) const;
    36.  
    37. private slots:
    38. // gets connected to m_albumManager's albumRemoved() signal
    39. void onAlbumRemoved(const int &albumId);
    40. void onCardAdded(const int &albumId, const QString &cardId);
    41. void onCardRemoved(const int &albumId, const QString &cardId);
    42.  
    43. private:
    44. AlbumsManager *m_albumsManager; // Points to the Album's AlbumsManager
    45. Album m_album; // Holds the Album it provides the View with
    46. };
    47.  
    48. #endif // ALBUMCARDSMODEL_H
    To copy to clipboard, switch view to plain text mode 

    Qt Code:
    1. #include "albumcardsmodel.h"
    2. AlbumCardsModel::AlbumCardsModel(QObject *parent)
    3. : AbstractCardModel(parent)
    4. {
    5. qDebug() << "[AlbumCardsModel] [called] [Default Constructor]";
    6. this->m_albumsManager = nullptr;
    7. this->m_cardsManager = nullptr;
    8. }
    9.  
    10.  
    11. AlbumCardsModel::AlbumCardsModel( AlbumsManager* albumsManager, CardsManager* cardsManager, QObject *parent)
    12. : AbstractCardModel(cardsManager, parent)
    13. {
    14. qDebug() << "[AlbumCardsModel] [called] [Overloaded Constructor]";
    15. this->m_albumsManager = albumsManager;
    16. this->m_cardsManager = cardsManager;
    17. }
    18.  
    19. // Show a specific Album
    20. void AlbumCardsModel::showAlbum(const int &albumId)
    21. {
    22. qDebug() << "[AlbumCardsModel] [called] >> showAlbum(const int &albumId) || albumId: " << albumId;
    23. // Get the requested Album from AlbumsManager and set it as the current active one.
    24. beginResetModel();
    25. m_album = m_albumsManager->album(albumId);
    26. endResetModel();
    27. }
    28.  
    29. // Get the number of Cards in the Active Album
    30. int AlbumCardsModel::rowCount(const QModelIndex&) const
    31. {
    32. qDebug() << "[AlbumCardsModel] [called] >> rowCount(const QModelIndex&)";
    33. return m_album.getCardIDs().count();
    34. }
    35.  
    36. // Get the card object at the specified position in the Album
    37. Card AlbumCardsModel::cardForIndex(const QModelIndex &index) const
    38. {
    39. qDebug() << "[AlbumCardsModel] [called] >> cardForIndex(const QModelIndex &index)";
    40. return m_cardsManager->card(m_album.getCardIDs().at(index.row()));
    41. }
    42.  
    43. // Receives a signal from the AlbumsManager when an Album is removed
    44. void AlbumCardsModel::onAlbumRemoved(const int &albumId)
    45. {
    46. qDebug() << "[AlbumCardsModel] [called] [from signal] >> onAlbumRemoved(const int &albumId) || albumId: " << albumId;
    47. // Do not proceed if the signaled Album change is not the active one
    48. if (albumId != m_album.getAlbumId()) return;
    49.  
    50. qDebug() << "[AlbumCardsModel] [update] >> onAlbumRemoved(const int &albumId) || albumId from signal matches current albumId.";
    51.  
    52. // replace the Model's active Album with a Default Album
    53. beginResetModel();
    54. m_album = Album();
    55. endResetModel();
    56. qDebug() << "[AlbumCardsModel] [update] >> onAlbumRemoved(const int &albumId) || Current album replaced with default constructed album.";
    57. }
    58.  
    59. // Receives a signal from the AlbumsManager when a Card is added to an Album
    60. void AlbumCardsModel::onCardAdded(const int &albumId, const QString &cardId)
    61. {
    62. qDebug() << "[AlbumCardsModel] [called] [from signal] >> onCardAdded(const int &albumId, const QString &cardId) || albumId: " << albumId << ", cardId: " << cardId;
    63. // Do not proceed if the signaled Album change is not the active one
    64. if (albumId != m_album.getAlbumId()) return;
    65.  
    66. qDebug() << "[AlbumCardsModel] [update] >> onCardAdded(const int &albumId, const QString &cardId) || albumId from signal matches current albumId";
    67.  
    68. // Retreive the updated Album from the AlbumsManager
    69. const Album updatedAlbum = m_albumsManager->album(albumId);
    70. const int row = updatedAlbum.getCardIDs().indexOf(cardId);
    71.  
    72. // replace the Model's active Album with the updated Album
    73. beginInsertRows(QModelIndex(), row, row);
    74. m_album = updatedAlbum;
    75. endInsertRows();
    76. qDebug() << "[AlbumCardsModel] [update] >> onCardAdded(const int &albumId, const QString &cardId) || current album updated";
    77. }
    78.  
    79. // Receives a signal from the AlbumsManager when a Card is removed from an Album
    80. void AlbumCardsModel::onCardRemoved(const int &albumId, const QString &cardId)
    81. {
    82. qDebug() << "[AlbumCardsModel] [called] [from signal] >> onCardRemoved(const int &albumId, const QString &cardId) || albumId: " << albumId << ", cardId: " << cardId;
    83. // Do not proceed if the signaled Album change is not the active one
    84. if (albumId != m_album.getAlbumId()) return;
    85.  
    86. qDebug() << "[AlbumCardsModel] [update] >> onCardRemoved(const int &albumId, const QString &cardId): albumId from signal matches current albumId";
    87.  
    88. // Retreive the updated Album from the AlbumsManager
    89. const Album updatedAlbum = m_albumsManager->album(albumId);
    90. const int row = updatedAlbum.getCardIDs().indexOf(cardId);
    91.  
    92. // replace the Model's active Album with the updated Album
    93. beginRemoveRows(QModelIndex(), row, row);
    94. m_album = updatedAlbum;
    95. endRemoveRows();
    96. qDebug() << "[AlbumCardsModel] [update] >> onCardRemoved(const int &albumId, const QString &cardId): current album updated";
    97. }
    To copy to clipboard, switch view to plain text mode 

    AlbumsManager:

    Qt Code:
    1. #ifndef ALBUMSMANAGER_H
    2. #define ALBUMSMANAGER_H
    3. #include "album.h"
    4. #include "card.h"
    5. #include <QObject>
    6. #include <QString>
    7. #include <QVariant>
    8. #include <QList>
    9. #include <QDebug>
    10. #include <QAbstractListModel>
    11. #include <QQmlListProperty>
    12. #include <QModelIndex>
    13.  
    14. /* This class manages the Albums used by the program.
    15.  * It contains all instances of Album objects and provides
    16.  * signals to views when a change to any of them has been
    17.  * made in order to refresh the views.
    18.  * AlbumsManager enherits from QAbstractList model to better manage
    19.  * the row insertion & removal in it's list of Albums. */
    20.  
    21. class AlbumsManager/* : public QAbstractListModel*/ : public QObject
    22. {
    23. Q_OBJECT // Used to register Type
    24.  
    25. public:
    26. // Default Constructor
    27. AlbumsManager(QObject* parent = 0);
    28.  
    29. // Copy Constructor
    30. AlbumsManager(const AlbumsManager& source);
    31.  
    32. // Assignment Operator
    33. AlbumsManager& operator=(const AlbumsManager& source);
    34.  
    35. // Retreives a specific Album from it's list
    36. Album album(const int &id) const;
    37.  
    38. // Retreives all Albums in it's list
    39. QList<Album> albums() const;
    40.  
    41. // Gets the nr. of Albums in it's list
    42. Q_INVOKABLE int count() const;
    43.  
    44. // Creates a new Album and adds it to the list
    45. Q_INVOKABLE void createAlbum(const QString &name);
    46.  
    47. // Add or remove specific Card to specified Album
    48. Q_INVOKABLE void addCard(const int &albumId, const QString &cardId);
    49. Q_INVOKABLE void removeCard(const int &albumId, const QString &cardId);
    50.  
    51. // Default Destructor
    52. ~AlbumsManager();
    53.  
    54. signals:
    55. // Signals to notify Model classes on changes
    56. void albumAdded(const int &id);
    57. void albumRemoved(const int &id);
    58. void cardAdded(const int &albumId, const QStringList &cardIDs);
    59. void cardRemoved(const int &albumId, const QStringList &cardIDs);
    60.  
    61. private:
    62. int m_albumId; // Provides unique IDs for Album creation by incrementation
    63. QList<int> m_albumIDs; // Holds list of used Album IDs
    64. QList<Album> m_albums; // Holds instances of Album objects it manages
    65. };
    66.  
    67. #endif // ALBUMSMANAGER_H
    To copy to clipboard, switch view to plain text mode 

    Qt Code:
    1. #include "albumsmanager.h"
    2.  
    3. // Default Constructor
    4. AlbumsManager::AlbumsManager(QObject* parent): /*QAbstractListModel(parent)*/ QObject(parent)
    5. {
    6. // Instanciate variable used for providing unique Album IDs
    7. this->m_albumId = 0;
    8.  
    9. // For debugging purposes
    10. qDebug() << "[AlbumsManager] [called] [constructor] || m_albumId set to: " << m_albumId;
    11. }
    12.  
    13. // Copy Constructor
    14. AlbumsManager::AlbumsManager(const AlbumsManager& source)
    15. {
    16. qDebug() << "[AlbumsManager] [called] [Copy Constructor]";
    17. this->m_albumId = source.m_albumId;
    18. this->m_albumIDs = source.m_albumIDs;
    19. this->m_albums = source.m_albums;
    20. }
    21.  
    22. // Assignment Operator
    23. AlbumsManager& AlbumsManager::operator=(const AlbumsManager& source)
    24. {
    25. qDebug() << "[AlbumsManager] [called] [Assignment Operator]";
    26. if(this != &source)
    27. {
    28. this->m_albumId = source.m_albumId;
    29. this->m_albumIDs = source.m_albumIDs;
    30. this->m_albums = source.m_albums;
    31. }
    32. return *this;
    33. }
    34.  
    35.  
    36. // Retreives a specific Album from it's list
    37. Album AlbumsManager::album(const int &id) const
    38. {
    39. // For debugging purposes
    40. qDebug() << "[AlbumsManager] [called] >> album(const int &id) || id: " << id;
    41.  
    42. // Find if an album in the list matches the provided Album ID
    43. int albumMatch;
    44. bool albumFound = false;
    45. for(int i = 0; i < this->count(); i++)
    46. {
    47. if(m_albums[i].getAlbumId() == id)
    48. {
    49. albumFound = true;
    50. albumMatch = i;
    51. }
    52. }
    53.  
    54. // If a match has been found, return the matching Album
    55. if(albumFound == true)
    56. {
    57. // For debugging purposes
    58. qDebug() << "[AlbumsManager] [update] >> album(const int &id) || Match found: " << albumMatch;
    59. qDebug() << "[AlbumsManager] [update] >> album(const int &id) || Returning Album Object";
    60. return this->m_albums[albumMatch];
    61. }
    62.  
    63. // If no match found, return a Default Album instance with no ID
    64. else
    65. {
    66. // For debugging purposes
    67. qDebug() << "[AlbumsManager] [update] >> album(const int &id) || No match found.";
    68. qDebug() << "[AlbumsManager] [update] >> album(const int &id) || Returning New Default Constructed Album() object";
    69. return Album();
    70. }
    71. }
    72.  
    73. // Retreives an Album Objects list of all the Albums in it's list
    74. QList<Album> AlbumsManager::albums() const
    75. {
    76. // For debugging purposes
    77. qDebug() << "[AlbumsManager] [called] >> albums()";
    78.  
    79. return this->m_albums;
    80. }
    81.  
    82. // Gets the nr. of Albums in it's list
    83. int AlbumsManager::count() const
    84. {
    85. // For debugging purposes
    86. qDebug() << "[AlbumsManager] [called] >> count() || returned: " << m_albums.count();
    87.  
    88. return this->m_albums.count();
    89. }
    90.  
    91. // Create new Album and Add it to the Album list this class manages
    92. void AlbumsManager::createAlbum(const QString &name)
    93. {
    94. // For debugging purposes
    95. qDebug() << "[AlbumsManager] [called] >> createAlbum(const QString &name) || name: " + name;
    96.  
    97. // Create new ID for the new album
    98. this->m_albumId++;
    99. this->m_albumIDs.append(m_albumId);
    100. qDebug() << "[AlbumsManager] [update] >> createAlbum(const QString &name) || Assigning albumId: " << m_albumId << " to newAlbum";
    101. qDebug() << "[AlbumsManager] [update] >> createAlbum(const QString &name) || calling Overloaded Album constructor, name: " << name << ", m_albumId: " << m_albumId;
    102.  
    103. // Create album using new ID and user specified Album name
    104. Album newAlbum(name,m_albumId);
    105.  
    106. // Add the new Album to the end of the Albums list
    107. m_albums << newAlbum;
    108. qDebug() << "[AlbumsManager] [update] >> createAlbum(const QString &name) || newAlbum appended to m_albums";
    109.  
    110.  
    111. // Send signal to notify views about the change
    112. albumAdded(m_albumId);
    113.  
    114. // // return the new Album
    115. // return newAlbum;
    116. }
    117.  
    118. // Add a specific Card to a specified Album
    119. void AlbumsManager::addCard(const int &albumId, const QString &cardId)
    120. {
    121. // For debugging purposes
    122. qDebug() << "[AlbumsManager] [called] >> addCard(const int &albumId, const QString &cardId) || albumId: " << albumId << ", cardId: " << cardId;
    123.  
    124. // Find if an album in the list matches the provided Album ID
    125. bool albumFound = false;
    126. int albumMatch;
    127. for(int i = 0; i < this->count(); i++)
    128. {
    129. if(m_albums[i].getAlbumId() == albumId)
    130. {
    131. albumFound = true;
    132. albumMatch = i;
    133. }
    134. }
    135.  
    136. // If a match has been found add specified card to it and send a signal to Models about the new change.
    137. if(albumFound == true)
    138. {
    139. qDebug() << "[AlbumsManager] [update] >> addCard(const int &albumId, const QString &cardId) || A matching Album was found.";
    140. this->m_albums[albumMatch].addCard(cardId);
    141. cardAdded(albumId, m_albums[albumMatch].getCardIDs());
    142. }
    143. else
    144. {
    145. qDebug() << "[AlbumsManager] [update] >> addCard(const int &albumId, const QString &cardId) || No matching Albums were found";
    146. }
    147. }
    148.  
    149. // Remove a specific Card from a specified Album
    150. void AlbumsManager::removeCard(const int &albumId, const QString &cardId)
    151. {
    152. // For debugging purposes
    153. qDebug() << "[AlbumsManager] [called] >> removeCard(const int &albumId, const QString &cardId) || albumId: " << albumId << ", cardId: " << cardId;
    154.  
    155. // Find if an album in the list matches the provided Album ID
    156. bool albumFound = false;
    157. int albumMatch;
    158. for(int i = 0; i < this->count(); i++)
    159. {
    160. if(m_albums[i].getAlbumId() == albumId)
    161. {
    162. albumFound = true;
    163. albumMatch = i;
    164. }
    165. }
    166.  
    167. // If a match has been found remove specified card from it and send a signal to Models about the new change
    168. if(albumFound == true)
    169. {
    170. qDebug() << "[AlbumsManager] [update] >> removeCard(const int &albumId, const QString &cardId) || A matching Album was found";
    171. this->m_albums[albumMatch].removeCard(cardId);
    172. cardRemoved(albumId, m_albums[albumMatch].getCardIDs());
    173. }
    174. else
    175. {
    176. qDebug() << "[AlbumsManager] [update] >> removeCard(const int &albumId, const QString &cardId) || No matching Albums were found";
    177. }
    178. }
    179.  
    180. // Default Destructor
    181. AlbumsManager::~AlbumsManager()
    182. {
    183. // For debugging purposes
    184. qDebug() << "[AlbumsManager] [called] [Destructor].";
    185. }
    To copy to clipboard, switch view to plain text mode 

    App:

    Qt Code:
    1. #ifndef APP_H
    2. #define APP_H
    3. #include <QObject>
    4. #include <QDebug>
    5. #include <QString>
    6. #include <QVariant>
    7. #include <QList>
    8. #include "album.h"
    9. #include "card.h"
    10. #include "albumsmanager.h"
    11. #include "cardsmanager.h"
    12. #include "albumcardsmodel.h"
    13. #include "abstractcardmodel.h"
    14. class App: public QObject
    15. {
    16. Q_OBJECT
    17.  
    18. public:
    19. // Constructor
    20. explicit App(QObject *parent = 0);
    21.  
    22. // Roles
    23. enum AlbumRoles { albumNameRole = Qt::UserRole + 1 };
    24.  
    25. // Getters
    26. AlbumsManager* getAlbumsManagerPointer();
    27. CardsManager* getCardsManagerPointer();
    28. AlbumCardsModel* getAlbumCardsModelPointer();
    29.  
    30. // Append
    31. void addAlbum(const Album &album);
    32.  
    33. // Position
    34. int rowCount(const QModelIndex & parent = QModelIndex()) const;
    35.  
    36. // Data from child items
    37. QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;
    38.  
    39. // Destructor
    40. ~App();
    41.  
    42. protected:
    43. // Role names
    44. QHash<int, QByteArray> roleNames() const;
    45.  
    46. private:
    47. // Children
    48. QList<Album> m_albums;
    49.  
    50. // New
    51. AlbumsManager m_albumsManager;
    52. CardsManager m_cardsManager;
    53. AlbumCardsModel m_albumCardsModel;
    54.  
    55. AlbumsManager* m_albumsManagerPointer;
    56. CardsManager* m_cardsManagerPointer;
    57. AlbumCardsModel* m_albumCardsModelPointer;
    58.  
    59. };
    60.  
    61. #endif // APP_H
    To copy to clipboard, switch view to plain text mode 

    Qt Code:
    1. #include "app.h"
    2.  
    3. // Default Constructor
    4. App::App(QObject *parent): QObject(parent)
    5. {
    6. // For debugging purposes
    7. qDebug() << "[App] [called] [Default Constructor]";
    8. this->m_albumsManager = AlbumsManager();
    9. this->m_albumsManagerPointer = &m_albumsManager;
    10.  
    11. this->m_cardsManager = CardsManager();
    12. this->m_cardsManagerPointer = &m_cardsManager;
    13.  
    14. this->m_albumCardsModel = AlbumCardsModel(m_albumsManagerPointer, m_cardsManagerPointer);
    15. this->m_albumCardsModelPointer = &m_albumCardsModel;
    16. }
    17.  
    18. // Getters
    19.  
    20. AlbumsManager* App::getAlbumsManagerPointer()
    21. {
    22. return this->m_albumsManagerPointer;
    23. }
    24.  
    25. CardsManager* App::getCardsManagerPointer()
    26. {
    27. return this->m_cardsManagerPointer;
    28. }
    29.  
    30. AlbumCardsModel* App::getAlbumCardsModelPointer()
    31. {
    32. return this->m_albumCardsModelPointer;
    33. }
    34.  
    35. // Append
    36. void App::addAlbum(const Album &album)
    37. {
    38. // For debugging purposes
    39. qDebug() << "[App] [called] >> addAlbum(const Album &album) || albumId: " << album.getAlbumId();
    40.  
    41. m_albums.append(album);
    42. }
    43.  
    44. // Position
    45. int App::rowCount(const QModelIndex & parent) const
    46. {
    47. // For debugging purposes
    48. qDebug() << "[App] [called] >> rowCount(const QModelIndex & parent) || Returning count: " << m_albums.count();
    49.  
    50. Q_UNUSED(parent);
    51. return m_albums.count();
    52. }
    53.  
    54. // Data
    55. QVariant App::data(const QModelIndex & index, int role) const
    56. {
    57. // For debugging purposes
    58. qDebug() << "[App] [called] >> data(const QModelIndex & index, int role)";
    59.  
    60. if (index.row() < 0 || index.row() >= m_albums.count())
    61. return QVariant();
    62.  
    63. const Album &album = m_albums[index.row()];
    64. if (role == albumNameRole)
    65. return album.getAlbumName();
    66. return QVariant();
    67. }
    68.  
    69. QHash<int, QByteArray> App::roleNames() const
    70. {
    71. // For debugging purposes
    72. qDebug() << "[App] [called] >> roleNames()";
    73.  
    74. QHash<int, QByteArray> roles;
    75. roles[albumNameRole] = "albumName";
    76. return roles;
    77. }
    78.  
    79. App::~App()
    80. {
    81. // For debugging purposes
    82. qDebug() << "[App] [called] [Default Destructor]";
    83. }
    To copy to clipboard, switch view to plain text mode 

    Card:

    Qt Code:
    1. #ifndef CARD_H
    2. #define CARD_H
    3. #include <QString>
    4. #include <QObject>
    5. #include <QDebug>
    6.  
    7. class Card : public QObject
    8. {
    9. private:
    10. QString cardID;
    11. QString name;
    12. QString imageURL;
    13. QString subtype;