1 #pragma once
2 
3 #include <QString>
4 #include <QMetaType>
5 
6 
7 // DTO for storing the actual and total number of tracks for an album.
8 // Both numbers are 1-based and 0 indicates an undefined value.
9 class TrackNumbers final {
10 public:
11     static constexpr int kValueUndefined = 0;
12     static constexpr int kValueMin = 1; // lower bound (inclusive)
13 
14     // Separates the total number of tracks from the actual
15     // track number in the textual format.
16     static const QString kSeparator;
17 
isUndefinedValue(int value)18     static bool isUndefinedValue(int value) {
19         return kValueUndefined == value;
20     }
21 
isValidValue(int value)22     static bool isValidValue(int value) {
23         return isUndefinedValue(value) || (kValueMin <= value);
24     }
25 
26     // Parses a value from a string. Returns true if the value
27     // has been parsed successfully and (optionally) stores the
28     // result in pValue. The caller is still responsible to check
29     // if the resulting value is valid!
30     static bool parseValueFromString(
31             const QString& str,
32             int* pValue = nullptr);
33 
34     explicit TrackNumbers(int actualValue = kValueUndefined, int totalValue = kValueUndefined)
m_actualValue(actualValue)35         : m_actualValue(actualValue),
36           m_totalValue(totalValue) {
37     }
38 
hasActual()39     bool hasActual() const {
40         return !isUndefinedValue(m_actualValue);
41     }
isActualValid()42     bool isActualValid() const {
43         return isValidValue(m_actualValue);
44     }
getActual()45     int getActual() const {
46         return m_actualValue;
47     }
setActual(int actualValue)48     void setActual(int actualValue) {
49         m_actualValue = actualValue;
50     }
51 
hasTotal()52     bool hasTotal() const {
53         return !isUndefinedValue(m_totalValue);
54     }
isTotalValid()55     bool isTotalValid() const {
56         return isValidValue(m_totalValue);
57     }
getTotal()58     int getTotal() const {
59         return m_totalValue;
60     }
setTotal(int totalValue)61     void setTotal(int totalValue) {
62         m_totalValue = totalValue;
63     }
64 
isValid()65     bool isValid() const {
66         return isActualValid() && isTotalValid();
67     }
68 
69     enum class ParseResult {
70         EMPTY,
71         VALID,
72         INVALID
73     };
74 
75     // Creates a new instance from string(s).
76     // If the caller is only interested in the ParseResult
77     // a nullptr can be passed for the corresponding output
78     // parameter pParsed.
79     static ParseResult parseFromStrings(
80             const QString& actualText,
81             const QString& totalText,
82             TrackNumbers* pParsed = nullptr);
83     static ParseResult parseFromString(
84             const QString& str,
85             TrackNumbers* pParsed = nullptr);
86 
87     // Formats this instance as string(s).
88     // Both output parameters pActualText and pTotalText
89     // are optional and the caller might pass a nullptr.
90     void toStrings(
91             QString* pActualText,
92             QString* pTotalText) const;
93     QString toString() const;
94 
95     // Splits a string into actual and total part. Both
96     // output parameters pActualText and pTotalText are
97     // optional and the caller might pass a nullptr.
98     static void splitString(
99             const QString& str,
100             QString* pActualText = nullptr,
101             QString* pTotalText = nullptr);
102     // Joins the actual and total strings
103     static QString joinAsString(
104             const QString& actualText,
105             const QString& totalText);
106 
107 private:
108     int m_actualValue;
109     int m_totalValue;
110 };
111 
112 inline
113 bool operator==(const TrackNumbers& lhs, const TrackNumbers& rhs) {
114     return (lhs.getActual() == rhs.getActual()) &&
115             (lhs.getTotal() == rhs.getTotal());
116 }
117 
118 inline
119 bool operator!=(const TrackNumbers& lhs, const TrackNumbers& rhs) {
120     return !(lhs == rhs);
121 }
122 
123 Q_DECLARE_TYPEINFO(TrackNumbers, Q_MOVABLE_TYPE);
124 Q_DECLARE_METATYPE(TrackNumbers)
125