diff options
author | Daniel Poelzleithner <git@poelzi.org> | 2020-12-05 20:43:10 +0100 |
---|---|---|
committer | Daniel Poelzleithner <git@poelzi.org> | 2020-12-05 20:43:10 +0100 |
commit | 0c8c24161486372c2787d9a881b07ce57e2e49cf (patch) | |
tree | 43258743284a0ece373935e17c0d01cb5023360e /src | |
parent | edc52841de58ad23c5e9d3833afdb65f5865b97e (diff) | |
parent | bf343d2677f19d1886682c4bd15e26f70884ce27 (diff) |
Merge branch '2.3' of https://github.com/mixxxdj/mixxx into rating-reset
Diffstat (limited to 'src')
-rw-r--r-- | src/library/basetracktablemodel.cpp | 371 | ||||
-rw-r--r-- | src/library/basetracktablemodel.h | 52 | ||||
-rw-r--r-- | src/library/starrating.cpp | 16 | ||||
-rw-r--r-- | src/library/starrating.h | 27 | ||||
-rw-r--r-- | src/preferences/dialog/dlgprefwaveform.cpp | 3 | ||||
-rw-r--r-- | src/track/trackrecord.h | 9 | ||||
-rw-r--r-- | src/util/sandbox.cpp | 24 | ||||
-rw-r--r-- | src/waveform/waveformwidgetfactory.cpp | 10 | ||||
-rw-r--r-- | src/widget/wnumberrate.cpp | 27 |
9 files changed, 386 insertions, 153 deletions
diff --git a/src/library/basetracktablemodel.cpp b/src/library/basetracktablemodel.cpp index 01b26920e0..bff1873cb2 100644 --- a/src/library/basetracktablemodel.cpp +++ b/src/library/basetracktablemodel.cpp @@ -402,19 +402,14 @@ QVariant BaseTrackTableModel::data( } if (role == Qt::BackgroundRole) { - QModelIndex colorIndex = index.sibling( - index.row(), - fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_COLOR)); - if (!colorIndex.isValid()) { + const auto rgbColorValue = rawSiblingValue( + index, + ColumnCache::COLUMN_LIBRARYTABLE_COLOR); + const auto rgbColor = mixxx::RgbColor::fromQVariant(rgbColorValue); + if (!rgbColor) { return QVariant(); } - const auto trackColor = - mixxx::RgbColor::fromQVariant( - rawValue(colorIndex)); - if (!trackColor) { - return QVariant(); - } - auto bgColor = mixxx::RgbColor::toQColor(trackColor); + auto bgColor = mixxx::RgbColor::toQColor(rgbColor); DEBUG_ASSERT(bgColor.isValid()); DEBUG_ASSERT(m_backgroundColorOpacity >= 0.0); DEBUG_ASSERT(m_backgroundColorOpacity <= 1.0); @@ -433,23 +428,65 @@ QVariant BaseTrackTableModel::data( return roleValue(index, rawValue(index), role); } +QVariant BaseTrackTableModel::rawValue( + const QModelIndex& index) const { + VERIFY_OR_DEBUG_ASSERT(index.isValid()) { + return QVariant(); + } + const auto field = mapColumn(index.column()); + if (field == ColumnCache::COLUMN_LIBRARYTABLE_INVALID) { + return QVariant(); + } + return rawSiblingValue(index, field); +} + +QVariant BaseTrackTableModel::rawSiblingValue( + const QModelIndex& index, + ColumnCache::Column siblingField) const { + VERIFY_OR_DEBUG_ASSERT(index.isValid()) { + return QVariant(); + } + VERIFY_OR_DEBUG_ASSERT(siblingField != ColumnCache::COLUMN_LIBRARYTABLE_INVALID) { + return QVariant(); + } + const auto siblingColumn = fieldIndex(siblingField); + DEBUG_ASSERT(siblingColumn >= 0); + VERIFY_OR_DEBUG_ASSERT(siblingColumn != index.column()) { + // Prevent infinite recursion + return QVariant(); + } + const auto siblingIndex = index.sibling(index.row(), siblingColumn); + return rawValue(siblingIndex); +} + bool BaseTrackTableModel::setData( const QModelIndex& index, const QVariant& value, int role) { const int column = index.column(); - - // Override sets to TIMESPLAYED and redirect them to PLAYED if (role == Qt::CheckStateRole) { - const auto val = value.toInt() > 0; - if (column == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_TIMESPLAYED)) { - QModelIndex playedIndex = index.sibling(index.row(), fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_PLAYED)); - return setData(playedIndex, val, Qt::EditRole); - } else if (column == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_BPM)) { - QModelIndex bpmLockindex = index.sibling(index.row(), fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_BPM_LOCK)); - return setData(bpmLockindex, val, Qt::EditRole); + const auto field = mapColumn(index.column()); + if (field == ColumnCache::COLUMN_LIBRARYTABLE_INVALID) { + return false; + } + const auto checked = value.toInt() > 0; + switch (field) { + case ColumnCache::COLUMN_LIBRARYTABLE_TIMESPLAYED: { + // Override sets to TIMESPLAYED and redirect them to PLAYED + QModelIndex playedIndex = index.sibling( + index.row(), + fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_PLAYED)); + return setData(playedIndex, checked, Qt::EditRole); + } + case ColumnCache::COLUMN_LIBRARYTABLE_BPM: { + QModelIndex bpmLockedIndex = index.sibling( + index.row(), + fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_BPM_LOCK)); + return setData(bpmLockedIndex, checked, Qt::EditRole); + } + default: + return false; } - return false; } TrackPointer pTrack = getTrack(index); @@ -499,133 +536,263 @@ QVariant BaseTrackTableModel::roleValue( const QModelIndex& index, QVariant&& rawValue, int role) const { - const int column = index.column(); - // Format the value based on whether we are in a tooltip, - // display, or edit role + const auto field = mapColumn(index.column()); + if (field == ColumnCache::COLUMN_LIBRARYTABLE_INVALID) { + return std::move(rawValue); + } switch (role) { case Qt::ToolTipRole: - if (column == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_COLOR)) { + switch (field) { + case ColumnCache::COLUMN_LIBRARYTABLE_COLOR: return mixxx::RgbColor::toQString(mixxx::RgbColor::fromQVariant(rawValue)); - } else if (column == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_COVERART)) { + case ColumnCache::COLUMN_LIBRARYTABLE_COVERART: return composeCoverArtToolTipHtml(index); - } else if (column == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_PREVIEW)) { + case ColumnCache::COLUMN_LIBRARYTABLE_PREVIEW: return QVariant(); + default: + // Same value as for Qt::DisplayRole (see below) + break; } M_FALLTHROUGH_INTENDED; case Qt::DisplayRole: - if (column == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_DURATION)) { - bool ok; - const auto duration = rawValue.toDouble(&ok); - if (ok && duration >= 0) { - return mixxx::Duration::formatTime( - duration, - mixxx::Duration::Precision::SECONDS); + switch (field) { + case ColumnCache::COLUMN_LIBRARYTABLE_DURATION: { + if (rawValue.isNull()) { + return QVariant(); + } + double durationInSeconds; + if (rawValue.canConvert<mixxx::Duration>()) { + const auto duration = rawValue.value<mixxx::Duration>(); + VERIFY_OR_DEBUG_ASSERT(duration >= mixxx::Duration::empty()) { + return QVariant(); + } + durationInSeconds = duration.toDoubleSeconds(); } else { + VERIFY_OR_DEBUG_ASSERT(rawValue.canConvert<double>()) { + return QVariant(); + } + bool ok; + durationInSeconds = rawValue.toDouble(&ok); + VERIFY_OR_DEBUG_ASSERT(ok && durationInSeconds >= 0) { + return QVariant(); + } + } + return mixxx::Duration::formatTime( + durationInSeconds, + mixxx::Duration::Precision::SECONDS); + } + case ColumnCache::COLUMN_LIBRARYTABLE_RATING: { + if (rawValue.isNull()) { return QVariant(); } - } else if (column == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_RATING)) { - VERIFY_OR_DEBUG_ASSERT(rawValue.canConvert(QMetaType::Int)) { + VERIFY_OR_DEBUG_ASSERT(rawValue.canConvert<int>()) { return QVariant(); } - return QVariant::fromValue(StarRating(rawValue.toInt())); - } else if (column == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_PLAYED)) { - return rawValue.toBool(); - } else if (column == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_TIMESPLAYED)) { - VERIFY_OR_DEBUG_ASSERT(rawValue.canConvert(QMetaType::Int)) { + bool ok; + const auto starCount = rawValue.toInt(&ok); + VERIFY_OR_DEBUG_ASSERT(ok && starCount >= StarRating::kMinStarCount) { + return QVariant(); + } + return QVariant::fromValue(StarRating(starCount)); + } + case ColumnCache::COLUMN_LIBRARYTABLE_TIMESPLAYED: { + if (rawValue.isNull()) { + return QVariant(); + } + VERIFY_OR_DEBUG_ASSERT(rawValue.canConvert<int>()) { return QVariant(); } - return QString("(%1)").arg(rawValue.toInt()); - } else if (column == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_DATETIMEADDED) || - column == fieldIndex(ColumnCache::COLUMN_PLAYLISTTRACKSTABLE_DATETIMEADDED)) { - return mixxx::localDateTimeFromUtc(mixxx::convertVariantToDateTime(rawValue)); - } else if (column == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_BPM)) { bool ok; - const auto bpmValue = rawValue.toDouble(&ok); - if (ok && bpmValue > 0.0) { - return QString("%1").arg(bpmValue, 0, 'f', 1); + const auto timesPlayed = rawValue.toInt(&ok); + VERIFY_OR_DEBUG_ASSERT(ok && timesPlayed >= 0) { + return QVariant(); + } + return QString("(%1)").arg(timesPlayed); + } + case ColumnCache::COLUMN_LIBRARYTABLE_DATETIMEADDED: + case ColumnCache::COLUMN_PLAYLISTTRACKSTABLE_DATETIMEADDED: + VERIFY_OR_DEBUG_ASSERT(rawValue.canConvert<QDateTime>()) { + return QVariant(); + } + return mixxx::localDateTimeFromUtc(rawValue.toDateTime()); + case ColumnCache::COLUMN_LIBRARYTABLE_BPM: { + mixxx::Bpm bpm; + if (!rawValue.isNull()) { + if (rawValue.canConvert<mixxx::Bpm>()) { + bpm = rawValue.value<mixxx::Bpm>(); + } else { + VERIFY_OR_DEBUG_ASSERT(rawValue.canConvert<double>()) { + return QVariant(); + } + bool ok; + const auto bpmValue = rawValue.toDouble(&ok); + VERIFY_OR_DEBUG_ASSERT(ok) { + return QVariant(); + } + bpm = mixxx::Bpm(bpmValue); + } + } + if (bpm.hasValue()) { + return QString("%1").arg(bpm.getValue(), 0, 'f', 1); } else { return QChar('-'); } - } else if (column == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_BPM_LOCK)) { - return rawValue.toBool(); - } else if (column == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_YEAR)) { - return mixxx::TrackMetadata::formatCalendarYear(rawValue.toString()); - } else if (column == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_TRACKNUMBER)) { - const auto trackNumber = rawValue.toInt(0); - if (trackNumber > 0) { - return std::move(rawValue); - } else { - // clear invalid values + } + case ColumnCache::COLUMN_LIBRARYTABLE_YEAR: { + if (rawValue.isNull()) { + return QVariant(); + } + VERIFY_OR_DEBUG_ASSERT(rawValue.canConvert<QString>()) { + return QVariant(); + } + bool ok; + const auto year = mixxx::TrackMetadata::formatCalendarYear(rawValue.toString(), &ok); + if (!ok) { return QVariant(); } - } else if (column == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_BITRATE)) { - int bitrateValue = rawValue.toInt(0); - if (bitrateValue > 0) { + return year; + } + case ColumnCache::COLUMN_LIBRARYTABLE_BITRATE: { + if (rawValue.isNull()) { + return QVariant(); + } + if (rawValue.canConvert<mixxx::audio::Bitrate>()) { + // return value as is return std::move(rawValue); } else { - // clear invalid values - return QVariant(); + VERIFY_OR_DEBUG_ASSERT(rawValue.canConvert<int>()) { + return QVariant(); + } + bool ok; + const auto bitrateValue = rawValue.toInt(&ok); + VERIFY_OR_DEBUG_ASSERT(ok) { + return QVariant(); + } + if (mixxx::audio::Bitrate(bitrateValue).isValid()) { + // return value as is + return std::move(rawValue); + } else { + // clear invalid values + return QVariant(); + } } - } else if (column == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_KEY)) { + } + case ColumnCache::COLUMN_LIBRARYTABLE_KEY: { // If we know the semantic key via the LIBRARYTABLE_KEY_ID // column (as opposed to the string representation of the key // currently stored in the DB) then lookup the key and render it // using the user's selected notation. - int keyIdColumn = fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_KEY_ID); - if (keyIdColumn == -1) { - // Otherwise, just use the column value + const QVariant keyCodeValue = rawSiblingValue( + index, + ColumnCache::COLUMN_LIBRARYTABLE_KEY_ID); + if (keyCodeValue.isNull()) { + // Otherwise, just use the column value as is return std::move(rawValue); } - mixxx::track::io::key::ChromaticKey key = - KeyUtils::keyFromNumericValue( - index.sibling(index.row(), keyIdColumn).data().toInt()); + // Convert or clear invalid values + VERIFY_OR_DEBUG_ASSERT(keyCodeValue.canConvert<int>()) { + return QVariant(); + } + bool ok; + const auto keyCode = keyCodeValue.toInt(&ok); + VERIFY_OR_DEBUG_ASSERT(ok) { + return QVariant(); + } + const auto key = KeyUtils::keyFromNumericValue(keyCode); if (key == mixxx::track::io::key::INVALID) { - // clear invalid values return QVariant(); } - // Render this key with the user-provided notation. + // Render the key with the user-provided notation return KeyUtils::keyToString(key); - } else if (column == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_REPLAYGAIN)) { - bool ok; - const auto gainValue = rawValue.toDouble(&ok); - return ok ? mixxx::ReplayGain::ratioToString(gainValue) : QString(); } - // Otherwise, just use the column value + case ColumnCache::COLUMN_LIBRARYTABLE_REPLAYGAIN: { + if (rawValue.isNull()) { + return QVariant(); + } + double rgRatio; + if (rawValue.canConvert<mixxx::ReplayGain>()) { + rgRatio = rawValue.value<mixxx::ReplayGain>().getRatio(); + } else { + VERIFY_OR_DEBUG_ASSERT(rawValue.canConvert<double>()) { + return QVariant(); + } + bool ok; + rgRatio = rawValue.toDouble(&ok); + VERIFY_OR_DEBUG_ASSERT(ok) { + return QVariant(); + } + } + return mixxx::ReplayGain::ratioToString(rgRatio); + } + case ColumnCache::COLUMN_LIBRARYTABLE_CHANNELS: + // Not yet supported + DEBUG_ASSERT(rawValue.isNull()); + break; + case ColumnCache::COLUMN_LIBRARYTABLE_SAMPLERATE: + // Not yet supported + DEBUG_ASSERT(rawValue.isNull()); + break; + case ColumnCache::COLUMN_LIBRARYTABLE_URL: + // Not yet supported + DEBUG_ASSERT(rawValue.isNull()); + break; + default: + // Otherwise, just use the column value + break; + } break; case Qt::EditRole: - if (column == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_BPM)) { + switch (field) { + case ColumnCache::COLUMN_LIBRARYTABLE_BPM: { bool ok; const auto bpmValue = rawValue.toDouble(&ok); - return ok ? bpmValue : 0.0; - } else if (column == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_TIMESPLAYED)) { + return ok ? bpmValue : mixxx::Bpm().getValue(); + } + case ColumnCache::COLUMN_LIBRARYTABLE_TIMESPLAYED: return index.sibling( - index.row(), fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_PLAYED)) - .data() - .toBool(); - } else if (column == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_RATING)) { - VERIFY_OR_DEBUG_ASSERT(rawValue.canConvert(QMetaType::Int)) { + index.row(), + fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_PLAYED)) + .data() + .toBool(); + case ColumnCache::COLUMN_LIBRARYTABLE_RATING: + VERIFY_OR_DEBUG_ASSERT(rawValue.canConvert<int>()) { return QVariant(); } return QVariant::fromValue(StarRating(rawValue.toInt())); + default: + // Otherwise, just use the column value + break; } - // Otherwise, just use the column value break; - case Qt::CheckStateRole: - if (column == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_TIMESPLAYED)) { - bool played = index.sibling( - index.row(), fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_PLAYED)) - .data() - .toBool(); - return played ? Qt::Checked : Qt::Unchecked; - } else if (column == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_BPM)) { - bool locked = index.sibling( - index.row(), fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_BPM_LOCK)) - .data() - .toBool(); - return locked ? Qt::Checked : Qt::Unchecked; + case Qt::CheckStateRole: { + QVariant boolValue; + switch (field) { + case ColumnCache::COLUMN_LIBRARYTABLE_PREVIEW: + boolValue = rawValue; + break; + case ColumnCache::COLUMN_LIBRARYTABLE_TIMESPLAYED: + boolValue = rawSiblingValue( + index, + ColumnCache::COLUMN_LIBRARYTABLE_PLAYED); + break; + case ColumnCache::COLUMN_LIBRARYTABLE_BPM: + boolValue = rawSiblingValue( + index, + ColumnCache::COLUMN_LIBRARYTABLE_BPM_LOCK); + break; + default: + // No check state supported + return QVariant(); } - // No check state supported - return QVariant(); + // Flags in the database are stored as integers that are + // convertible to bool. + if (!boolValue.isNull() && boolValue.canConvert<bool>()) { + return boolValue.toBool() ? Qt::Checked : Qt::Unchecked; + } else { + // Undecidable + return Qt::PartiallyChecked; + } + } default: DEBUG_ASSERT(!"unexpected role"); break; diff --git a/src/library/basetracktablemodel.h b/src/library/basetracktablemodel.h index a771213f1e..d45923b518 100644 --- a/src/library/basetracktablemodel.h +++ b/src/library/basetracktablemodel.h @@ -149,8 +149,58 @@ class BaseTrackTableModel : public QAbstractTableModel, public TrackModel { virtual Qt::ItemFlags readWriteFlags( const QModelIndex& index) const; + /// At least one of the following functions must be overridden, + /// because each default implementation will call the other + /// function!! + /// + /// Return the raw data value at the given index. + /// + /// Expected types by ColumnCache field (pass-through = not validated): + /// COLUMN_LIBRARYTABLE_ID: DbId::value_type (pass-through) + /// COLUMN_LIBRARYTABLE_ARTIST: QString (pass-through) + /// COLUMN_LIBRARYTABLE_TITLE: QString (pass-through) + /// COLUMN_LIBRARYTABLE_ALBUM: QString (pass-through) + /// COLUMN_LIBRARYTABLE_ALBUMARTIST: QString (pass-through) + /// COLUMN_LIBRARYTABLE_YEAR: QString (pass-through) + /// COLUMN_LIBRARYTABLE_GENRE: QString (pass-through) + /// COLUMN_LIBRARYTABLE_COMPOSER: QString (pass-through) + /// COLUMN_LIBRARYTABLE_GROUPING: QString (pass-through) + /// COLUMN_LIBRARYTABLE_TRACKNUMBER: QString (pass-through) + /// COLUMN_LIBRARYTABLE_FILETYPE: QString (pass-through) + /// COLUMN_LIBRARYTABLE_NATIVELOCATION: QString (pass-through) + /// COLUMN_LIBRARYTABLE_COMMENT: QString (pass-through) + /// COLUMN_LIBRARYTABLE_DURATION: double (seconds)/mixxx::Duration + /// COLUMN_LIBRARYTABLE_BITRATE: int (kbps)/mixxx::audio::Bitrate + /// COLUMN_LIBRARYTABLE_BPM: double (beats per minute)/mixxx::Bpm + /// COLUMN_LIBRARYTABLE_REPLAYGAIN: double (ratio)/mixxx::ReplayGain + /// COLUMN_LIBRARYTABLE_URL: QString (unsupported) + /// COLUMN_LIBRARYTABLE_SAMPLERATE: int (Hz)/mixxx::audio::SampleRate (unsupported) + /// COLUMN_LIBRARYTABLE_WAVESUMMARYHEX: QVariant (pass-through) + /// COLUMN_LIBRARYTABLE_CHANNELS: int/mixxx::audio::ChannelCount (unsupported) + /// COLUMN_LIBRARYTABLE_MIXXXDELETED: bool (pass-through) + /// COLUMN_LIBRARYTABLE_DATETIMEADDED: QDateTime + /// COLUMN_LIBRARYTABLE_HEADERPARSED: bool (pass-through) + /// COLUMN_LIBRARYTABLE_TIMESPLAYED: int + /// COLUMN_LIBRARYTABLE_PLAYED: bool + /// COLUMN_LIBRARYTABLE_RATING: int + /// COLUMN_LIBRARYTABLE_KEY: QString (literal key name, pass-through) + /// COLUMN_LIBRARYTABLE_KEY_ID: int (internal key code) + /// COLUMN_LIBRARYTABLE_BPM_LOCK: bool + /// COLUMN_LIBRARYTABLE_PREVIEW: bool + /// COLUMN_LIBRARYTABLE_COLOR: mixxx::RgbColor::code_t + /// COLUMN_LIBRARYTABLE_COVERART: virtual column for CoverArtDelegate + /// COLUMN_LIBRARYTABLE_COVERART_SOURCE: int (pass-through) + /// COLUMN_LIBRARYTABLE_COVERART_TYPE: int (pass-through) + /// COLUMN_LIBRARYTABLE_COVERART_LOCATION: QString (pass-through) + /// COLUMN_LIBRARYTABLE_COVERART_COLOR: mixxx::RgbColor::code_t (pass-through) + /// COLUMN_LIBRARYTABLE_COVERART_DIGEST: QByteArray (pass-through) + /// COLUMN_LIBRARYTABLE_COVERART_HASH: quint16 (pass-through) + /// COLUMN_PLAYLISTTABLE_DATETIMEADDED: QDateTime virtual QVariant rawValue( - const QModelIndex& index) const = 0; + const QModelIndex& index) const; + virtual QVariant rawSiblingValue( + const QModelIndex& index, + ColumnCache::Column siblingField) const; // Reimplement in derived classes to handle columns other // then COLUMN_LIBRARYTABLE diff --git a/src/library/starrating.cpp b/src/library/starrating.cpp index a64941482a..c062b28b70 100644 --- a/src/library/starrating.cpp +++ b/src/library/starrating.cpp @@ -8,9 +8,13 @@ // Magic number? Explain what this factor affects and how const int PaintingScaleFactor = 15; -StarRating::StarRating(int starCount, int maxStarCount) - : m_myStarCount(starCount), - m_myMaxStarCount(maxStarCount) { +StarRating::StarRating( + int starCount, + int maxStarCount) + : m_starCount(starCount), + m_maxStarCount(maxStarCount) { + DEBUG_ASSERT(m_starCount >= kMinStarCount); + DEBUG_ASSERT(m_starCount <= m_maxStarCount); // 1st star cusp at 0° of the unit circle whose center is shifted to adapt the 0,0-based paint area m_starPolygon << QPointF(1.0, 0.5); for (int i = 1; i < 5; ++i) { @@ -26,7 +30,7 @@ StarRating::StarRating(int starCount, int maxStarCount) } QSize StarRating::sizeHint() const { - return PaintingScaleFactor * QSize(m_myMaxStarCount, 1); + return PaintingScaleFactor * QSize(m_maxStarCount, 1); } void StarRating::paint(QPainter *painter, const QRect &rect) const { @@ -41,8 +45,8 @@ void StarRating::paint(QPainter *painter, const QRect &rect) const { //determine number of stars that are possible to paint int n = rect.width() / PaintingScaleFactor; - for (int i = 0; i < m_myMaxStarCount && i<n; ++i) { - if (i < m_myStarCount) { + for (int i = 0; i < m_maxStarCount && i < n; ++i) { + if (i < m_starCount) { painter->drawPolygon(m_starPolygon, Qt::WindingFill); } else { painter->drawPolygon(m_diamondPolygon, Qt::WindingFill); diff --git a/src/library/starrating.h b/src/library/starrating.h index df21447758..2a7d131945 100644 --- a/src/library/starrating.h +++ b/src/library/starrating.h @@ -4,6 +4,8 @@ #include <QPolygonF> #include <QSize> +#include "track/trackrecord.h" + QT_FORWARD_DECLARE_CLASS(QPainter); QT_FORWARD_DECLARE_CLASS(QRect); @@ -18,21 +20,32 @@ class StarRating { public: enum EditMode { Editable, ReadOnly }; - StarRating(int starCount = 1, int maxStarCount = 5); + static constexpr int kMinStarCount = 0; + + explicit StarRating( + int starCount = kMinStarCount, + int maxStarCount = mixxx::TrackRecord::kMaxRating - mixxx::TrackRecord::kMinRating); void paint(QPainter* painter, const QRect& rect) const; QSize sizeHint() const; - int starCount() const { return m_myStarCount; } - int maxStarCount() const { return m_myMaxStarCount; } - void setStarCount(int starCount) { m_myStarCount = starCount; } - void setMaxStarCount(int maxStarCount) { m_myMaxStarCount = maxStarCount; } + int starCount() const { + return m_starCount; + } + int maxStarCount() const { + return m_maxStarCount; + } + void setStarCount(int starCount) { + DEBUG_ASSERT(starCount >= kMinStarCount); + DEBUG_ASSERT(starCount <= m_maxStarCount); + m_starCount = starCount; + } private: QPolygonF m_starPolygon; QPolygonF m_diamondPolygon; - int m_myStarCount; - int m_myMaxStarCount; + int m_starCount; + int m_maxStarCount; }; Q_DECLARE_METATYPE(StarRating) diff --git a/src/preferences/dialog/dlgprefwaveform.cpp b/src/preferences/dialog/dlgprefwaveform.cpp index 75e376082d..2c79c91f24 100644 --- a/src/preferences/dialog/dlgprefwaveform.cpp +++ b/src/preferences/dialog/dlgprefwaveform.cpp @@ -215,8 +215,7 @@ void DlgPrefWaveform::slotResetToDefaults() { // Default zoom level is 3 in WaveformWidgetFactory. defaultZoomComboBox->setCurrentIndex(3 + 1); - // Don't synchronize zoom by default. - synchronizeZoomCheckBox->setChecked(false); + synchronizeZoomCheckBox->setChecked(true); // RGB overview. waveformOverviewComboBox->setCurrentIndex(2); diff --git a/src/track/trackrecord.h b/src/track/trackrecord.h index 1a9d2ae369..bf819acc64 100644 --- a/src/track/trackrecord.h +++ b/src/track/trackrecord.h @@ -66,8 +66,15 @@ class TrackRecord final { TrackRecord& operator=(TrackRecord&&) = default; TrackRecord& operator=(const TrackRecord&) = default; + static constexpr int kMinRating = 0; + static constexpr int kMaxRating = 5; + static constexpr int kNoRating = kMinRating; + + static bool isValidRating(int rating) { + return rating >= kMinRating && rating <= kMaxRating; + } bool hasRating() const { - return getRating() > 0; + return getRating() != kNoRating; } void setKeys(const Keys& keys); diff --git a/src/util/sandbox.cpp b/src/util/sandbox.cpp index 2dc305cacb..e229a927fa 100644 --- a/src/util/sandbox.cpp +++ b/src/util/sandbox.cpp @@ -30,14 +30,9 @@ void Sandbox::initialize(const QString& permissionsFile) { s_pSandboxPermissions = QSharedPointer<ConfigObject<ConfigValue>>( new ConfigObject<ConfigValue>(permissionsFile)); -#ifdef Q_OS_MAC -#if __MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 - // If we are running on at least 10.7.0 and have the com.apple.security.app-sandbox - // entitlement, we are in a sandbox - SInt32 version = 0; - Gestalt(gestaltSystemVersion, &version); +#ifdef __APPLE__ SecCodeRef secCodeSelf; - if (version >= 0x1070 && SecCodeCopySelf(kSecCSDefaultFlags, &secCodeSelf) == errSecSuccess) { + if (SecCodeCopySelf(kSecCSDefaultFlags, &secCodeSelf) == errSecSuccess) { SecRequirementRef sandboxReq; CFStringRef entitlement = CFSTR("entitlement [\"com.apple.security.app-sandbox\"]"); if (SecRequirementCreateWithString(entitlement, kSecCSDefaultFlags, @@ -51,7 +46,6 @@ void Sandbox::initialize(const QString& permissionsFile) { CFRelease(secCodeSelf); } #endif -#endif } // static @@ -156,8 +150,7 @@ bool Sandbox::createSecurityToken(const QString& canonicalPath, return false; } -#ifdef Q_OS_MAC -#if __MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 +#ifdef __APPLE__ CFURLRef url = CFURLCreateWithFileSystemPath( kCFAllocatorDefault, QStringToCFString(canonicalPath), kCFURLPOSIXPathStyle, isDirectory); @@ -192,7 +185,6 @@ bool Sandbox::createSecurityToken(const QString& canonicalPath, } } #endif -#endif return false; } @@ -322,8 +314,7 @@ SecurityTokenPointer Sandbox::openSecurityToken(const QDir& dir, bool create) { SecurityTokenPointer Sandbox::openTokenFromBookmark(const QString& canonicalPath, const QString& bookmarkBase64) { -#ifdef Q_OS_MAC -#if __MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 +#ifdef __APPLE__ QByteArray bookmarkBA = QByteArray::fromBase64(bookmarkBase64.toLatin1()); if (!bookmarkBA.isEmpty()) { CFDataRef bookmarkData = CFDataCreate( @@ -360,7 +351,6 @@ SecurityTokenPointer Sandbox::openTokenFromBookmark(const QString& canonicalPath } } } -#endif #else Q_UNUSED(canonicalPath); Q_UNUSED(bookmarkBase64); @@ -369,7 +359,7 @@ SecurityTokenPointer Sandbox::openTokenFromBookmark(const QString& canonicalPath return SecurityTokenPointer(); } -#ifdef Q_OS_MAC +#ifdef __APPLE__ SandboxSecurityToken::SandboxSecurityToken(const QString& path, CFURLRef url) : m_path(path), m_url(url) { @@ -382,16 +372,14 @@ SandboxSecurityToken::SandboxSecurityToken(const QString& path, CFURLRef url) #endif SandboxSecurityToken::~SandboxSecurityToken() { -#ifdef Q_OS_MAC +#ifdef __APPLE__ if (sDebug) { qDebug() << "~SandboxSecurityToken" << m_path; } -#if __MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 if (m_url) { CFURLStopAccessingSecurityScopedResource(m_url); CFRelease(m_url); m_url = 0; } #endif -#endif } diff --git a/src/waveform/waveformwidgetfactory.cpp b/src/waveform/waveformwidgetfactory.cpp index 4d8a7062f3..17988e5856 100644 --- a/src/waveform/waveformwidgetfactory.cpp +++ b/src/waveform/waveformwidgetfactory.cpp @@ -105,7 +105,7 @@ WaveformWidgetFactory::WaveformWidgetFactory() m_frameRate(30), m_endOfTrackWarningTime(30), m_defaultZoom(WaveformWidgetRenderer::s_waveformDefaultZoom), - m_zoomSync(false), + m_zoomSync(true), m_overviewNormalized(false), m_openGlAvailable(false), m_openGlesAvailable(false), @@ -303,12 +303,8 @@ bool WaveformWidgetFactory::setConfig(UserSettingsPointer config) { m_config->set(ConfigKey("[Waveform]","DefaultZoom"), ConfigValue(m_defaultZoom)); } - int zoomSync = m_config->getValueString(ConfigKey("[Waveform]","ZoomSynchronization")).toInt(&ok); - if (ok) { - setZoomSync(static_cast<bool>(zoomSync)); - } else { - m_config->set(ConfigKey("[Waveform]","ZoomSynchronization"), ConfigValue(m_zoomSync)); - } + bool zoomSync = m_config->getValue(ConfigKey("[Waveform]", "ZoomSynchronization"), m_zoomSync); + setZoomSync(zoomSync); int beatGridAlpha = m_config->getValue(ConfigKey("[Waveform]", "beatGridAlpha"), m_beatGridAlpha); setDisplayBeatGridAlpha(beatGridAlpha); diff --git a/src/widget/wnumberrate.cpp b/src/widget/wnumberrate.cpp index 048e840c91..04ce8c18bd 100644 --- a/src/widget/wnumberrate.cpp +++ b/src/widget/wnumberrate.cpp @@ -16,6 +16,20 @@ #include "control/controlproxy.h" #include "util/math.h" +namespace { + +inline QChar sign(double number) { + if (number > 0) { + return '+'; + } + if (number < 0) { + return '-'; + } + return ' '; +} + +} // namespace + WNumberRate::WNumberRate(const QString& group, QWidget* parent) : WNumber(parent) { m_pRateRatio = new ControlProxy(group, "rate_ratio", this, ControlFlag::NoAssertIfMissing); @@ -30,13 +44,8 @@ void WNumberRate::setup(const QDomNode& node, const SkinContext& context) { } void WNumberRate::setValue(double dValue) { - double vsign = dValue - 1; - - char sign = '+'; - if (vsign < -0.00000001) { - sign = '-'; - } - - setText(QString(m_skinText).append(sign) - .append("%1").arg(fabs(vsign) * 100.0, 0, 'f', m_iNoDigits)); + const double digitFactor = pow(10, m_iNoDigits); + // Calculate percentage rounded to the number of digits specified by iNoDigits + const double percentage = round((dValue - 1) * 100.0 * digitFactor) / digitFactor; + setText(m_skinText + sign(percentage) + QString::number(fabs(percentage), 'f', m_iNoDigits)); } |