summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDaniel Poelzleithner <git@poelzi.org>2020-12-05 20:43:10 +0100
committerDaniel Poelzleithner <git@poelzi.org>2020-12-05 20:43:10 +0100
commit0c8c24161486372c2787d9a881b07ce57e2e49cf (patch)
tree43258743284a0ece373935e17c0d01cb5023360e /src
parentedc52841de58ad23c5e9d3833afdb65f5865b97e (diff)
parentbf343d2677f19d1886682c4bd15e26f70884ce27 (diff)
Merge branch '2.3' of https://github.com/mixxxdj/mixxx into rating-reset
Diffstat (limited to 'src')
-rw-r--r--src/library/basetracktablemodel.cpp371
-rw-r--r--src/library/basetracktablemodel.h52
-rw-r--r--src/library/starrating.cpp16
-rw-r--r--src/library/starrating.h27
-rw-r--r--src/preferences/dialog/dlgprefwaveform.cpp3
-rw-r--r--src/track/trackrecord.h9
-rw-r--r--src/util/sandbox.cpp24
-rw-r--r--src/waveform/waveformwidgetfactory.cpp10
-rw-r--r--src/widget/wnumberrate.cpp27
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));
}