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