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