1 /**
2  * \file frame.h
3  * Generalized frame.
4  *
5  * \b Project: Kid3
6  * \author Urs Fleisch
7  * \date 25 Aug 2007
8  *
9  * Copyright (C) 2007-2018  Urs Fleisch
10  *
11  * This file is part of Kid3.
12  *
13  * Kid3 is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 2 of the License, or
16  * (at your option) any later version.
17  *
18  * Kid3 is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
25  */
26 
27 #pragma once
28 
29 #include <QString>
30 #include <QVariant>
31 #include <QList>
32 #include <QSet>
33 #include <QHash>
34 #include <set>
35 #include "formatreplacer.h"
36 #include "framenotice.h"
37 #include "kid3api.h"
38 
39 /** Generalized frame. */
40 class KID3_CORE_EXPORT Frame {
41   Q_GADGET
42   Q_ENUMS(Type)
43   Q_ENUMS(FieldId)
44   Q_ENUMS(TextEncoding)
45   Q_ENUMS(PictureType)
46   Q_ENUMS(TagVersion)
47   Q_ENUMS(TagNumber)
48 public:
49   /** Generalized frame types. */
50   enum Type {
51     FT_Title,
52     FT_FirstFrame = FT_Title,
53     FT_Artist,
54     FT_Album,
55     FT_Comment,
56     FT_Date,
57     FT_Track,
58     FT_Genre,
59     FT_LastV1Frame = FT_Genre,
60     FT_AlbumArtist,
61     FT_Arranger,
62     FT_Author,
63     FT_Bpm,
64     FT_CatalogNumber,
65     FT_Compilation,
66     FT_Composer,
67     FT_Conductor,
68     FT_Copyright,
69     FT_Disc,
70     FT_EncodedBy,
71     FT_EncoderSettings,
72     FT_EncodingTime,
73     FT_Grouping,
74     FT_InitialKey,
75     FT_Isrc,
76     FT_Language,
77     FT_Lyricist,
78     FT_Lyrics,
79     FT_Media,
80     FT_Mood,
81     FT_OriginalAlbum,
82     FT_OriginalArtist,
83     FT_OriginalDate,
84     FT_Description,
85     FT_Performer,
86     FT_Picture,
87     FT_Publisher,
88     FT_ReleaseCountry,
89     FT_Remixer,
90     FT_SortAlbum,
91     FT_SortAlbumArtist,
92     FT_SortArtist,
93     FT_SortComposer,
94     FT_SortName,
95     FT_Subtitle,
96     FT_Website,
97     FT_WWWAudioFile,
98     FT_WWWAudioSource,
99     FT_ReleaseDate,
100     FT_Rating,
101     FT_Work,
102     FT_LastFrame = FT_Work,
103     FT_Other,
104     FT_UnknownFrame
105   };
106 
107   /**
108    * Types of fields in a frame, must be the same as id3lib's ID3_FieldID.
109    **/
110   enum FieldId {
111     ID_NoField,
112     ID_TextEnc,
113     ID_Text,
114     ID_Url,
115     ID_Data,
116     ID_Description,
117     ID_Owner,
118     ID_Email,
119     ID_Rating,
120     ID_Filename,
121     ID_Language,
122     ID_PictureType,
123     ID_ImageFormat,
124     ID_MimeType,
125     ID_Counter,
126     ID_Id,
127     ID_VolumeAdj,
128     ID_NumBits,
129     ID_VolChgRight,
130     ID_VolChgLeft,
131     ID_PeakVolRight,
132     ID_PeakVolLeft,
133     ID_TimestampFormat,
134     ID_ContentType,
135 
136     // These are additional fields used by TagLib
137     ID_Price,
138     ID_Date,
139     ID_Seller,
140 
141     // Additional field for METADATA_BLOCK_PICTURE
142     ID_ImageProperties,
143 
144     // Type of subframe in CTOC and CHAP frames
145     ID_Subframe
146   };
147 
148   /** Text encoding for fields of type ID_TextEnc. */
149   enum TextEncoding {
150     TE_ISO8859_1 = 0,
151     TE_UTF16 = 1,
152     TE_UTF16BE = 2,
153     TE_UTF8 = 3
154   };
155 
156   /** Picture type, compatible with ID3v2 and FLAC. */
157   enum PictureType {
158     PT_Other = 0,
159     PT_Png32Icon = 1,
160     PT_OtherIcon = 2,
161     PT_CoverFront = 3,
162     PT_CoverBack = 4,
163     PT_LeafletPage = 5,
164     PT_Media = 6,
165     PT_LeadArtist = 7,
166     PT_Artist = 8,
167     PT_Conductor = 9,
168     PT_Band = 10,
169     PT_Composer = 11,
170     PT_Lyricist = 12,
171     PT_RecordingLocation = 13,
172     PT_DuringRecording = 14,
173     PT_DuringPerformance = 15,
174     PT_Video = 16,
175     PT_Fish = 17,
176     PT_Illustration = 18,
177     PT_ArtistLogo = 19,
178     PT_PublisherLogo = 20
179   };
180 
181   /** Supported tags. */
182   enum TagNumber {
183     Tag_1,              /**< First tag */
184     Tag_2,              /**< Second tag */
185     Tag_3,              /**< Third tag */
186     Tag_NumValues,      /**< Total number of tags */
187 
188     // Special uses of tags
189     Tag_Id3v1 = Tag_1,  /**< Tag which can be ID3v1 tag */
190     Tag_Id3v2 = Tag_2,  /**< Tag which can be ID3v2 tag */
191     Tag_Picture = Tag_2 /**< Tag used for pictures */
192   };
193 
194   /** Tag version contained in track data. */
195   enum TagVersion {
196     TagNone = 0, /**< Empty or imported and not from a tag */
197     TagV1 = 1 << Tag_1,   /**< Tag 1 */
198     TagV2 = 1 << Tag_2,   /**< Tag 2 */
199     TagV3 = 1 << Tag_3,   /**< Tag 3 */
200     /** Tag 1 and 2 or merged from tag 2 and tag 1 (where tag 2 is not set) */
201     TagV2V1 = TagV1 | TagV2,
202     TagVAll = TagV1 | TagV2 | TagV3 /**< All tags */
203   };
204 
205   /**
206    * Cast a mask of tag version bits to a TagVersion enum.
207    * @param tagMask tag mask (bit 0 for tag 1, bit 1 for tag 2)
208    * @return tag version mask.
209    */
tagVersionCast(int tagMask)210   static TagVersion tagVersionCast(int tagMask) {
211     return static_cast<TagVersion>(tagMask & TagVAll);
212   }
213 
214   /**
215    * @brief Cast an integer to a tag number.
216    * @param nr number
217    * @return tag number, Tag_NumValues if invalid.
218    */
tagNumberCast(int nr)219   static TagNumber tagNumberCast(int nr) {
220     return nr >= Tag_1 && nr < Tag_NumValues
221         ? static_cast<TagNumber>(nr) : Tag_NumValues;
222   }
223 
224   /**
225    * Get a tag mask from a tag number.
226    * @param tagNr tag number
227    * @return tag version mask.
228    */
tagVersionFromNumber(TagNumber tagNr)229   static TagVersion tagVersionFromNumber(TagNumber tagNr) {
230     return tagNr < Tag_NumValues
231         ? static_cast<TagVersion>(1 << tagNr) : TagNone;
232   }
233 
234   /**
235    * Get list of available tag versions with translated description.
236    * @return tag version/description pairs.
237    */
238   static const QList<QPair<TagVersion, QString> > availableTagVersions();
239 
240   /**
241    * Get highest priority tag number which is set in a tag mask.
242    * @param tagMask tag mask with bits set for tags
243    * @return tag number, Tag_NumValues if no tag is set.
244    */
tagNumberFromMask(TagVersion tagMask)245   static TagNumber tagNumberFromMask(TagVersion tagMask) {
246     return (tagMask & TagV2)
247         ? Tag_2 : (tagMask & TagV1)
248           ? Tag_1 : (tagMask & TagV3)
249             ? Tag_3 : Tag_NumValues;
250   }
251 
252   /**
253    * Get tag numbers which are set in a tag mask, ordered from highest
254    * to lowest priority.
255    * @param tagMask tag mask with bits set for tags
256    * @return list of tag numbers.
257    */
tagNumbersFromMask(TagVersion tagMask)258   static const QList<TagNumber> tagNumbersFromMask(TagVersion tagMask) {
259     QList<TagNumber> result;
260     if (tagMask & TagV2) result << Tag_2;
261     if (tagMask & TagV1) result << Tag_1;
262     if (tagMask & TagV3) result << Tag_3;
263     return result;
264   }
265 
266   /**
267    * Get all tag numbers, ordered from highest to lowest priority.
268    * @return list of tag numbers.
269    */
allTagNumbers()270   static const QList<TagNumber> allTagNumbers() {
271     return tagNumbersFromMask(TagVAll);
272   }
273 
274   /**
275    * Get string representation for tag number.
276    * @param tagNr tag number
277    * @return "1" for Tag_1, "2" for Tag_2, ..., null if invalid.
278    */
279   static QString tagNumberToString(TagNumber tagNr);
280 
281   /**
282    * Get tag number from string representation.
283    * @param str string representation
284    * @return Tag_1 for "1", Tag_2 for "2", ..., Tag_NumValues if invalid.
285    */
286   static TagNumber tagNumberFromString(const QString& str);
287 
288 /** for loop through all TagNumber values. */
289 #define FOR_ALL_TAGS(variable) \
290   for (Frame::TagNumber variable = Frame::Tag_1; \
291        variable < Frame::Tag_NumValues; \
292        variable = static_cast<Frame::TagNumber>(variable + 1))
293 
294 /** for loop through TagNumber values set in mask. */
295 #define FOR_TAGS_IN_MASK(variable, mask) \
296   FOR_ALL_TAGS(variable) \
297     if ((mask) & (1 << variable))
298 
299   /** Field in frame. */
300   struct KID3_CORE_EXPORT Field {
301     /**
302      * Equality operator.
303      * @param rhs right hand side to compare
304      * @return true if this == rhs.
305      */
306     bool operator==(const Field& rhs) const {
307       return m_id == rhs.m_id && m_value == rhs.m_value;
308     }
309 
310     int m_id;         /**< type of field. */
311     QVariant m_value; /**< value of field. */
312 
313     /**
314      * Get a translated string for a field ID.
315      *
316      * @param type field ID type
317      *
318      * @return field ID type, null string if unknown.
319      */
320     static QString getFieldIdName(FieldId type);
321 
322     /**
323      * List of field ID strings, NULL terminated.
324      */
325     static const char* const* getFieldIdNames();
326 
327     /**
328      * Get field ID from field name.
329      * @param fieldName name of field, can be English or translated
330      * @return field ID, ID_NoField if not found.
331      */
332     static FieldId getFieldId(const QString& fieldName);
333 
334     /**
335      * Get a translated string for a text encoding.
336      *
337      * @param type text encoding type
338      *
339      * @return text encoding type, null string if unknown.
340      */
341     static QString getTextEncodingName(TextEncoding type);
342 
343     /**
344      * List of text encoding strings, NULL terminated.
345      */
346     static const char* const* getTextEncodingNames();
347 
348     /**
349      * Get a translated string for a timestamp format.
350      *
351      * @param type timestamp format type
352      *
353      * @return timestamp format type, null string if unknown.
354      */
355     static QString getTimestampFormatName(int type);
356 
357     /**
358      * List of timestamp format strings, NULL terminated.
359      */
360     static const char* const* getTimestampFormatNames();
361 
362     /**
363      * Get a translated string for a content type.
364      *
365      * @param type content type
366      *
367      * @return content type, null string if unknown.
368      */
369     static QString getContentTypeName(int type);
370 
371     /**
372      * List of content type strings, NULL terminated.
373      */
374     static const char* const* getContentTypeNames();
375 
376     /**
377      * Compare two field lists in a tolerant way.
378      * This function can be used instead of the standard QList equality
379      * operator if the field lists can be from different tag formats, which
380      * may not all support the same field types.
381      * @param fl1 first field list
382      * @param fl2 second field list
383      * @return true if they are similar enough.
384      */
385     static bool fuzzyCompareFieldLists(const QList<Field>& fl1,
386                                        const QList<Field>& fl2);
387 
388   };
389 
390   /** list of fields. */
391   typedef QList<Field> FieldList;
392 
393   /**
394    * Type and name of frame.
395    */
396   class KID3_CORE_EXPORT ExtendedType {
397   public:
398     /**
399      * Constructor.
400      */
ExtendedType()401     ExtendedType() : m_type(FT_UnknownFrame) {}
402 
403     /**
404      * Constructor.
405      * @param type type
406      * @param name internal name
407      */
ExtendedType(Type type,const QString & name)408     ExtendedType(Type type, const QString& name) : m_type(type), m_name(name) {}
409 
410     /**
411      * Constructor.
412      * @param name internal name
413      */
414     explicit ExtendedType(const QString& name);
415 
416     /**
417      * Constructor.
418      * @param type type
419      */
420     explicit ExtendedType(Type type);
421 
422     /**
423      * Get name of type.
424      * @return name.
425      */
426     QString getName() const;
427 
428     /**
429      * Get translated name of type.
430      * @return name.
431      */
432     QString getTranslatedName() const;
433 
434     /**
435      * Get internal name of type.
436      * @return name.
437      */
getInternalName()438     QString getInternalName() const { return m_name; }
439 
440     /**
441      * Less than operator.
442      * @param rhs right hand side to compare
443      * @return true if this < rhs.
444      */
445     bool operator<(const ExtendedType& rhs) const {
446       return m_type < rhs.m_type ||
447              (m_type == FT_Other && m_type == rhs.m_type && m_name < rhs.m_name);
448     }
449 
450     /**
451      * Equality operator.
452      * @param rhs right hand side to compare
453      * @return true if this == rhs.
454      */
455     bool operator==(const ExtendedType& rhs) const {
456       return m_type == rhs.m_type &&
457              (m_type != FT_Other || m_name == rhs.m_name);
458     }
459 
460     /**
461      * Get type
462      * @return type.
463      */
getType()464     Type getType() const { return m_type; }
465 
466   private:
467     friend class Frame;
468     Type m_type;
469     QString m_name;
470   };
471 
472 
473   /**
474    * Constructor.
475    */
476   Frame();
477 
478   /**
479    * Constructor.
480    * @param type  type
481    * @param value value
482    * @param name  internal name
483    * @param index index inside tag, -1 if unknown
484    */
485   Frame(Type type, const QString& value, const QString& name, int index);
486 
487   /**
488    * Constructor.
489    * @param type  type and internal name
490    * @param value value
491    * @param index index inside tag, -1 if unknown
492    */
493   Frame(const ExtendedType& type, const QString& value, int index);
494 
495   /**
496    * Less than operator.
497    * Needed for sorting in multiset.
498    * @param rhs right hand side to compare
499    * @return true if this < rhs.
500    */
501   bool operator<(const Frame& rhs) const {
502     return m_extendedType < rhs.m_extendedType;
503   }
504 
505 #ifdef Q_CC_MSVC
506   /**
507    * Equality operator.
508    * Needed when building with MSVC and BUILD_SHARED_LIBS.
509    * @param rhs right hand side to compare
510    * @return true if this == rhs.
511    */
512   bool operator==(const Frame& rhs) const {
513     return m_extendedType == rhs.m_extendedType && m_value == rhs.m_value &&
514       m_fieldList == rhs.m_fieldList;
515   }
516 #endif
517 
518   /**
519    * Get type of frame.
520    * @return type.
521    */
getType()522   Type getType() const { return m_extendedType.m_type; }
523 
524   /**
525    * Set type of frame.
526    * @param type type of frame
527    */
setType(Type type)528   void setType(Type type) { m_extendedType.m_type = type; }
529 
530   /**
531    * Get type and name of frame.
532    * @return extended type.
533    */
getExtendedType()534   ExtendedType getExtendedType() const { return m_extendedType; }
535 
536   /**
537    * Set type and name of frame.
538    * @param type extended type of frame
539    */
setExtendedType(const ExtendedType & type)540   void setExtendedType(const ExtendedType& type) { m_extendedType = type; }
541 
542   /**
543    * Get index of frame.
544    * @return index.
545    */
getIndex()546   int getIndex() const { return m_index; }
547 
548   /**
549    * Set index of frame.
550    * @param index index of frame
551    */
setIndex(int index)552   void setIndex(int index) { m_index = index; }
553 
554   /**
555    * Get name of frame.
556    * @return name.
557    */
getName()558   QString getName() const { return m_extendedType.getName(); }
559 
560   /**
561    * Get internal name of frame.
562    * @return name.
563    */
getInternalName()564   QString getInternalName() const { return m_extendedType.getInternalName(); }
565 
566   /**
567    * Get value as string.
568    * @return value.
569    */
getValue()570   QString getValue() const { return m_value; }
571 
572   /**
573    * Set value as string.
574    * @param value value as string
575    */
setValue(const QString & value)576   void setValue(const QString& value) { m_value = value; }
577 
578   /**
579    * Get value as integer.
580    * @return value.
581    */
582   int getValueAsNumber() const;
583 
584   /**
585    * Set value as integer.
586    * @param n value as number
587    */
588   void setValueAsNumber(int n);
589 
590   /**
591    * Check if value is empty.
592    * @return true if empty.
593    */
isEmpty()594   bool isEmpty() const { return m_value.isEmpty(); }
595 
596   /**
597    * Check if frame is inactive.
598    * @return true if inactive.
599    */
isInactive()600   bool isInactive() const { return m_value.isNull(); }
601 
602   /**
603    * Set frame inactive.
604    */
setInactive()605   void setInactive() { m_value = QString(); }
606 
607   /**
608    * Check if frame represents different frames in multiple files.
609    * @return true if different.
610    */
isDifferent()611   bool isDifferent() const { return m_value == differentRepresentation(); }
612 
613   /**
614    * Represents different frames in multiple files.
615    */
setDifferent()616   void setDifferent() { m_value = differentRepresentation(); }
617 
618   /**
619    * Get warning notice if frame is marked.
620    * @return notice.
621    */
getNotice()622   FrameNotice getNotice() const { return m_marked; }
623 
624   /**
625    * Check if frame is marked.
626    * @return true if marked.
627    */
isMarked()628   bool isMarked() const { return m_marked; }
629 
630   /**
631    * Mark frame.
632    * @param notice warning notice
633    */
setMarked(FrameNotice notice)634   void setMarked(FrameNotice notice) { m_marked = notice; }
635 
636   /**
637    * Check if value is changed.
638    * @return true if changed.
639    */
isValueChanged()640   bool isValueChanged() const { return m_valueChanged; }
641 
642   /**
643    * Mark the value as changed.
644    * @param changed true to mark as changed
645    */
646   void setValueChanged(bool changed = true) { m_valueChanged = changed; }
647 
648   /**
649    * Set value as string and mark it as changed if it is changed.
650    * This method will avoid setting "different" representations.
651    * @param value value as string
652    */
653   void setValueIfChanged(const QString& value);
654 
655   /**
656    * Set the value from a field in the field list.
657    */
658   void setValueFromFieldList();
659 
660   /**
661    * Set a field in the field list from the value.
662    */
663   void setFieldListFromValue();
664 
665   /**
666    * Get fields in the frame.
667    * @return field list.
668    */
getFieldList()669   const FieldList& getFieldList() const { return m_fieldList; }
670 
671   /**
672    * Set fields in the frame.
673    * @param fields field list
674    */
setFieldList(const FieldList & fields)675   void setFieldList(const FieldList& fields) { m_fieldList = fields; }
676 
677   /**
678    * Get fields in the frame.
679    * @return reference to field list.
680    */
fieldList()681   FieldList& fieldList() { return m_fieldList; }
682 
683   /**
684    * Get the value of a field.
685    *
686    * @param id field ID
687    *
688    * @return field value, invalid if field not found.
689    */
690   QVariant getFieldValue(FieldId id) const;
691 
692   /**
693    * Check if the fields in another frame are equal.
694    *
695    * @param other other frame
696    *
697    * @return true if equal.
698    */
699   bool isEqual(const Frame& other) const;
700 
701 #ifndef QT_NO_DEBUG
702   /**
703    * Dump contents of frame to debug console.
704    */
705   void dump() const;
706 #endif
707 
708   /**
709    * If a frame contains a string list as a value, it is stored in a single
710    * string, separated by this special separator character.
711    *
712    * @return separator character.
713    */
stringListSeparator()714   static QLatin1Char stringListSeparator() { return QLatin1Char('|'); }
715 
716   /**
717    * Convert string (e.g. "track/total number of tracks") to number.
718    *
719    * @param str string to convert
720    * @param ok  if not 0, true is returned here if conversion is ok
721    *
722    * @return number in string ignoring total after slash.
723    */
724   static int numberWithoutTotal(const QString& str, bool* ok = nullptr);
725 
726   /**
727    * Get representation of different frames in multiple files.
728    * @return "different" representation.
729    */
differentRepresentation()730   static QChar differentRepresentation() { return QChar(0x2260); }
731 
732   /**
733    * Set value of a field.
734    *
735    * @param frame frame to set
736    * @param id    field ID
737    * @param value field value
738    *
739    * @return true if field found and set.
740    */
741   static bool setField(Frame& frame, FieldId id, const QVariant& value);
742 
743   /**
744    * Set value of a field.
745    *
746    * @param frame frame to set
747    * @param fieldName name of field, can be English or translated
748    * @param value field value
749    *
750    * @return true if field found and set.
751    */
752   static bool setField(Frame& frame, const QString& fieldName,
753                        const QVariant& value);
754 
755   /**
756    * Get value of a field.
757    *
758    * @param frame frame to get
759    * @param id    field ID
760    *
761    * @return field value, invalid if not found.
762    */
763   static QVariant getField(const Frame& frame, FieldId id);
764 
765   /**
766    * Get value of a field.
767    *
768    * @param frame frame to get
769    * @param fieldName name of field, can be English or translated
770    *
771    * @return field value, invalid if not found.
772    */
773   static QVariant getField(const Frame& frame, const QString& fieldName);
774 
775   /**
776    * Get type of frame from English name.
777    *
778    * @param name name, spaces and case are ignored
779    *
780    * @return type.
781    */
782   static Type getTypeFromName(const QString& name);
783 
784   /**
785    * Get a translated string for a frame type.
786    *
787    * @param type frame type
788    *
789    * @return frame type, null string if unknown.
790    */
791   static QString getFrameTypeName(Type type);
792 
793   /**
794    * Get a display name for a frame name.
795    * @param name frame name as returned by getName()
796    * @return display name, transformed if necessary and translated.
797    */
798   static QString getDisplayName(const QString& name);
799 
800   /**
801    * Get a map with display names as keys and frame names as values.
802    * @param names frame names as returned by getName()
803    * @return mapping of display names to frame names.
804    */
805   static QMap<QString, QString> getDisplayNameMap(const QStringList& names);
806 
807   /**
808    * Get the frame name for a translated display name.
809    * @param name translated display name
810    * @return English frame name for @a name if found, else @a name.
811    */
812   static QString getNameForTranslatedFrameName(const QString& name);
813 
814   /**
815    * Convert frame index to a negative index used for a second collection.
816    * This can be a collection containing picture frames, the mapping is
817    * -1 -> -1, 0 -> -2, 1 -> -3, 2 -> -4, ...
818    * @param index positive index, -1 is the unknown index
819    * @return negative index <= -1.
820    */
toNegativeIndex(int index)821   static int toNegativeIndex(int index) { return -2 - index; }
822 
823   /**
824    * Convert negative index used for a second collection to a frame index.
825    * This can be used to get the index of a collection containing picture
826    * frames, the mapping is
827    * -1 -> -1, -2 -> 0, -3 -> 1, -4 -> 2, ...
828    * @param negativeIndex negative index, -1 is the unknown index
829    * @return frame negative >= -1.
830    */
fromNegativeIndex(int negativeIndex)831   static int fromNegativeIndex(int negativeIndex) { return -2 - negativeIndex; }
832 
833 private:
834   friend class TaggedFile;
835 
836   ExtendedType m_extendedType;
837   int m_index;
838   QString m_value;
839   FieldList m_fieldList;
840   FrameNotice m_marked;
841   bool m_valueChanged;
842 };
843 
844 /** Filter to enable a subset of frame types. */
845 class KID3_CORE_EXPORT FrameFilter {
846 public:
847   /**
848    * Constructor.
849    * All frames are disabled
850    */
851   FrameFilter();
852 
853   /**
854    * Enable all frames.
855    */
856   void enableAll();
857 
858   /**
859    * Check if all fields are true.
860    *
861    * @return true if all fields are true.
862    */
863   bool areAllEnabled() const;
864 
865   /**
866    * Check if frame is enabled.
867    *
868    * @param type frame type
869    * @param name frame name
870    *
871    * @return true if frame is enabled.
872    */
873   bool isEnabled(Frame::Type type, const QString& name = QString()) const;
874 
875   /**
876    * Enable or disable frame.
877    *
878    * @param type frame type
879    * @param name frame name
880    * @param en true to enable
881    */
882   void enable(Frame::Type type, const QString& name = QString(), bool en = true);
883 
884 private:
885   static const quint64 FTM_AllFrames = (1ULL << (Frame::FT_LastFrame + 1)) - 1;
886   quint64 m_enabledFrames;
887   std::set<QString> m_disabledOtherFrames;
888 };
889 
890 /** Collection of frames. */
891 class KID3_CORE_EXPORT FrameCollection : public std::multiset<Frame> {
892 public:
893   /**
894    * Default value for quick access frames.
895    */
896   static constexpr quint64 DEFAULT_QUICK_ACCESS_FRAMES =
897       (1ULL << Frame::FT_Title)   |
898       (1ULL << Frame::FT_Artist)  |
899       (1ULL << Frame::FT_Album)   |
900       (1ULL << Frame::FT_Comment) |
901       (1ULL << Frame::FT_Date)    |
902       (1ULL << Frame::FT_Track)   |
903       (1ULL << Frame::FT_Genre);
904 
905   /**
906    * Set values which are different inactive.
907    *
908    * @param others frames to compare, will be modified!
909    * @param differentValues optional storage for the different values
910    */
911   void filterDifferent(FrameCollection& others,
912           QHash<Frame::ExtendedType, QSet<QString>>* differentValues = nullptr);
913 
914   /**
915    * Add standard frames which are missing.
916    */
917   void addMissingStandardFrames();
918 
919   /**
920    * Copy enabled frames.
921    *
922    * @param flt filter with enabled frames
923    *
924    * @return copy with enabled frames.
925    */
926   FrameCollection copyEnabledFrames(const FrameFilter& flt) const;
927 
928   /**
929    * Remove all frames which are not enabled from the collection.
930    *
931    * @param flt filter with enabled frames
932    */
933   void removeDisabledFrames(const FrameFilter& flt);
934 
935   /**
936    * Set the index of all frames to -1.
937    */
938   void setIndexesInvalid();
939 
940   /**
941    * Copy frames which are empty or inactive from other frames.
942    * This can be used to merge two frame collections.
943    *
944    * @param frames other frames
945    */
946   void merge(const FrameCollection& frames);
947 
948   /**
949    * Check if the standard tags are empty or inactive.
950    *
951    * @return true if empty or inactive.
952    */
953   bool isEmptyOrInactive() const;
954 
955   /**
956    * Find a frame by name.
957    *
958    * @param name  the name of the frame to find, if the exact name is not
959    *              found, a case-insensitive search for the first name
960    *              starting with this string is performed
961    * @param index 0 for first frame with @a name, 1 for second, etc.
962    *
963    * @return iterator or end() if not found.
964    */
965   const_iterator findByName(const QString& name, int index = 0) const;
966 
967   /**
968    * Find a frame by type or name.
969    *
970    * @param type  type and name of the frame to find, if the exact name is not
971    *              found, a case-insensitive search for the first name
972    *              starting with this string is performed
973    * @param index 0 for first frame with @a type, 1 for second, etc.
974    *
975    * @return iterator or end() if not found.
976    */
977   const_iterator findByExtendedType(const Frame::ExtendedType& type,
978                                     int index = 0) const;
979 
980   /**
981    * Find a frame by index.
982    *
983    * @param index the index in the frame, see \ref Frame::getIndex()
984    *
985    * @return iterator or end() if not found.
986    */
987   const_iterator findByIndex(int index) const;
988 
989   /**
990    * Get value by type.
991    *
992    * @param type type
993    *
994    * @return value, QString::null if not found.
995    */
996   QString getValue(Frame::Type type) const;
997 
998   /**
999    * Get value by type and name.
1000    *
1001    * @param type  type and name of the frame to find, if the exact name is not
1002    *              found, a case-insensitive search for the first name
1003    *              starting with this string is performed
1004    *
1005    * @return value, QString::null if not found.
1006    */
1007   QString getValue(const Frame::ExtendedType& type) const;
1008 
1009   /**
1010    * Set value by type.
1011    *
1012    * @param type type
1013    * @param value value, nothing is done if QString::null
1014    */
1015   void setValue(Frame::Type type, const QString& value);
1016 
1017   /**
1018    * Set value by type and name.
1019    *
1020    * @param type  type and name of the frame to find, if the exact name is not
1021    *              found, a case-insensitive search for the first name
1022    *              starting with this string is performed
1023    * @param value value, nothing is done if QString::null
1024    */
1025   void setValue(const Frame::ExtendedType& type, const QString& value);
1026 
1027   /**
1028    * Get integer value by type.
1029    *
1030    * @param type type
1031    *
1032    * @return value, 0 if empty, -1 if not found.
1033    */
1034   int getIntValue(Frame::Type type) const;
1035 
1036   /**
1037    * Set integer value by type.
1038    *
1039    * @param type type
1040    * @param value value, 0 to set empty, nothing is done if -1
1041    */
1042   void setIntValue(Frame::Type type, int value);
1043 
1044   /**
1045    * Get artist.
1046    *
1047    * @return artist, QString::null if not found.
1048    */
getArtist()1049   QString getArtist() const { return getValue(Frame::FT_Artist); }
1050 
1051   /**
1052    * Set artist.
1053    *
1054    * @param artist artist, nothing is done if QString::null
1055    */
setArtist(const QString & artist)1056   void setArtist(const QString& artist) { setValue(Frame::FT_Artist, artist); }
1057 
1058   /**
1059    * Get album.
1060    *
1061    * @return album, QString::null if not found.
1062    */
getAlbum()1063   QString getAlbum() const { return getValue(Frame::FT_Album); }
1064 
1065   /**
1066    * Set album.
1067    *
1068    * @param album album, nothing is done if QString::null
1069    */
setAlbum(const QString & album)1070   void setAlbum(const QString& album) { setValue(Frame::FT_Album, album); }
1071 
1072   /**
1073    * Get title.
1074    *
1075    * @return title, QString::null if not found.
1076    */
getTitle()1077   QString getTitle() const { return getValue(Frame::FT_Title); }
1078 
1079   /**
1080    * Set title.
1081    *
1082    * @param title title, nothing is done if QString::null
1083    */
setTitle(const QString & title)1084   void setTitle(const QString& title) { setValue(Frame::FT_Title, title); }
1085 
1086   /**
1087    * Get comment.
1088    *
1089    * @return comment, QString::null if not found.
1090    */
getComment()1091   QString getComment() const { return getValue(Frame::FT_Comment); }
1092 
1093   /**
1094    * Set comment.
1095    *
1096    * @param comment comment, nothing is done if QString::null
1097    */
setComment(const QString & comment)1098   void setComment(const QString& comment) { setValue(Frame::FT_Comment, comment); }
1099 
1100   /**
1101    * Get genre.
1102    *
1103    * @return genre, QString::null if not found.
1104    */
getGenre()1105   QString getGenre() const { return getValue(Frame::FT_Genre); }
1106 
1107   /**
1108    * Set genre.
1109    *
1110    * @param genre genre, nothing is done if QString::null
1111    */
setGenre(const QString & genre)1112   void setGenre(const QString& genre) { setValue(Frame::FT_Genre, genre); }
1113 
1114   /**
1115    * Get track.
1116    *
1117    * @return track, -1 if not found.
1118    */
getTrack()1119   int getTrack() const { return getIntValue(Frame::FT_Track); }
1120 
1121   /**
1122    * Set track.
1123    *
1124    * @param track track, nothing is done if -1
1125    */
setTrack(int track)1126   void setTrack(int track) { setIntValue(Frame::FT_Track, track); }
1127 
1128   /**
1129    * Get year.
1130    *
1131    * @return year, -1 if not found.
1132    */
getYear()1133   int getYear() const { return getIntValue(Frame::FT_Date); }
1134 
1135   /**
1136    * Set year.
1137    *
1138    * @param year year, nothing is done if -1
1139    */
setYear(int year)1140   void setYear(int year) { setIntValue(Frame::FT_Date, year); }
1141 
1142   /**
1143    * Compare the frames with another frame collection and mark the value as
1144    * changed on frames which are different.
1145    *
1146    * @param other other frame collection
1147    */
1148   void markChangedFrames(const FrameCollection& other);
1149 
1150 #ifndef QT_NO_DEBUG
1151   /**
1152    * Dump contents of frame collection to debug console.
1153    */
1154   void dump() const;
1155 #endif
1156 
1157   /**
1158    * Set mask containing the bits of all frame types which shall be used as
1159    * quick access frames.
1160    * @param mask bit mask with bits for quick access frames set, default is
1161    * DEFAULT_QUICK_ACCESS_FRAMES.
1162    */
setQuickAccessFrames(quint64 mask)1163   static void setQuickAccessFrames(quint64 mask) {
1164     s_quickAccessFrames = mask;
1165   }
1166 
1167   /**
1168    * Get mask containing the bits of all frame types which shall be used as
1169    * quick access frames.
1170    * @return mask bit mask with bits for quick access frames set.
1171    */
getQuickAccessFrames()1172   static quint64 getQuickAccessFrames() {
1173     return s_quickAccessFrames;
1174   }
1175 
1176   /**
1177    * Create a frame collection from a list of subframe fields.
1178    *
1179    * The given subframe fields must start with a Frame::ID_Subframe field with
1180    * the frame name as its value, followed by the fields of the frame. More
1181    * subframes may follow.
1182    *
1183    * @param begin iterator to begin of subframes
1184    * @param end iterator after end of subframes
1185    *
1186    * @return frames constructed from subframe fields.
1187    */
1188   static FrameCollection fromSubframes(Frame::FieldList::const_iterator begin,
1189                                        Frame::FieldList::const_iterator end);
1190 
1191 private:
1192   /**
1193    * Search for a frame only by name.
1194    *
1195    * @param name the name of the frame to find, a case-insensitive search for
1196    *             the first name starting with this string is performed
1197    *
1198    * @return iterator or end() if not found.
1199    */
1200   const_iterator searchByName(const QString& name) const;
1201 
1202   /**
1203    * Bit mask containing the bits of all frame types which shall be used as
1204    * quick access frames.
1205    * This mask has to be handled like FrameFilter::m_enabledFrames.
1206    */
1207   static quint64 s_quickAccessFrames;
1208 };
1209 
1210 
1211 /**
1212  * Replaces frame format codes in a string.
1213  */
1214 class KID3_CORE_EXPORT FrameFormatReplacer : public FormatReplacer {
1215 public:
1216   /**
1217    * Constructor.
1218    *
1219    * @param frames frame collection
1220    * @param str    string with format codes
1221    */
1222   explicit FrameFormatReplacer(
1223     const FrameCollection& frames, const QString& str = QString());
1224 
1225   /**
1226    * Destructor.
1227    */
1228   virtual ~FrameFormatReplacer() override = default;
1229 
1230   FrameFormatReplacer(const FrameFormatReplacer& other) = delete;
1231   FrameFormatReplacer &operator=(const FrameFormatReplacer& other) = delete;
1232 
1233   /**
1234    * Get help text for supported format codes.
1235    *
1236    * @param onlyRows if true only the tr elements are returned,
1237    *                 not the surrounding table
1238    *
1239    * @return help text.
1240    */
1241   static QString getToolTip(bool onlyRows = false);
1242 
1243 protected:
1244   /**
1245    * Replace a format code (one character %c or multiple characters %{chars}).
1246    * Supported format fields:
1247    * %s title (song)
1248    * %l album
1249    * %a artist
1250    * %c comment
1251    * %y year
1252    * %t track, two digits, i.e. leading zero if < 10
1253    * %T track, without leading zeroes
1254    * %g genre
1255    *
1256    * @param code format code
1257    *
1258    * @return replacement string,
1259    *         QString::null if code not found.
1260    */
1261   virtual QString getReplacement(const QString& code) const override;
1262 
1263 private:
1264   const FrameCollection& m_frames;
1265 };
1266 
1267 /** Hash function to use Frame::ExtendedType as a QHash key. */
qHash(const Frame::ExtendedType & key)1268 inline uint qHash(const Frame::ExtendedType& key) {
1269   return qHash(key.getType()) ^ qHash(key.getInternalName());
1270 }
1271