1 #include "skin/skinloader.h"
2
3 #include <QApplication>
4 #include <QDir>
5 #include <QString>
6 #include <QtDebug>
7
8 #include "vinylcontrol/vinylcontrolmanager.h"
9 #include "skin/legacy/legacyskinparser.h"
10 #include "controllers/controllermanager.h"
11 #include "library/library.h"
12 #include "effects/effectsmanager.h"
13 #include "mixer/playermanager.h"
14 #include "util/debug.h"
15 #include "skin/legacy/launchimage.h"
16 #include "util/timer.h"
17 #include "recording/recordingmanager.h"
18
SkinLoader(UserSettingsPointer pConfig)19 SkinLoader::SkinLoader(UserSettingsPointer pConfig) :
20 m_pConfig(pConfig) {
21 }
22
~SkinLoader()23 SkinLoader::~SkinLoader() {
24 LegacySkinParser::clearSharedGroupStrings();
25 }
26
getSkinSearchPaths() const27 QList<QDir> SkinLoader::getSkinSearchPaths() const {
28 QList<QDir> searchPaths;
29
30 // Add user skin path to search paths
31 QDir userSkinsPath(m_pConfig->getSettingsPath());
32 if (userSkinsPath.cd("skins")) {
33 searchPaths.append(userSkinsPath);
34 }
35
36 // If we can't find the skins folder then we can't load a skin at all. This
37 // is a critical error in the user's Mixxx installation.
38 QDir skinsPath(m_pConfig->getResourcePath());
39 if (!skinsPath.cd("skins")) {
40 reportCriticalErrorAndQuit("Skin directory does not exist: " +
41 skinsPath.absoluteFilePath("skins"));
42 }
43 searchPaths.append(skinsPath);
44
45 return searchPaths;
46 }
47
getSkinPath(const QString & skinName) const48 QString SkinLoader::getSkinPath(const QString& skinName) const {
49 const QList<QDir> skinSearchPaths = getSkinSearchPaths();
50 for (QDir dir : skinSearchPaths) {
51 if (dir.cd(skinName)) {
52 if (!dir.exists("skin.xml")) {
53 qWarning() << "Skipping skin directory" << dir.absolutePath()
54 << "because \"skin.xml\" is missing";
55 continue;
56 }
57 return dir.absolutePath();
58 }
59 }
60 return QString();
61 }
62
getSkinPreview(const QString & skinName,const QString & schemeName,const double devicePixelRatio) const63 QPixmap SkinLoader::getSkinPreview(const QString& skinName,
64 const QString& schemeName,
65 const double devicePixelRatio) const {
66 QPixmap preview;
67 if (!schemeName.isEmpty()) {
68 QString schemeNameUnformatted = schemeName;
69 QString schemeNameFormatted = schemeNameUnformatted.replace(" ","");
70 preview.load(getSkinPath(skinName) + "/skin_preview_" + schemeNameFormatted + ".png");
71 } else {
72 preview.load(getSkinPath(skinName) + "/skin_preview.png");
73 }
74 if (preview.isNull()) {
75 preview.load(":/images/skin_preview_placeholder.png");
76 }
77 preview = preview.scaled(QSize(640, 360) * devicePixelRatio,
78 Qt::KeepAspectRatio,
79 Qt::SmoothTransformation);
80 preview.setDevicePixelRatio(devicePixelRatio);
81 return preview;
82 }
83
getConfiguredSkinPath() const84 QString SkinLoader::getConfiguredSkinPath() const {
85 QString configSkin = m_pConfig->getValueString(ConfigKey("[Config]", "ResizableSkin"));
86
87 // If we don't have a skin defined, we might be migrating from 1.11 and
88 // should pick the closest-possible skin.
89 if (configSkin.isEmpty()) {
90 QString oldSkin = m_pConfig->getValueString(ConfigKey("[Config]", "Skin"));
91 if (!oldSkin.isEmpty()) {
92 configSkin = pickResizableSkin(oldSkin);
93 }
94 // If the old skin was empty or we couldn't guess a skin, go with the
95 // default.
96 if (configSkin.isEmpty()) {
97 configSkin = getDefaultSkinName();
98 }
99 }
100
101 QString skinPath = getSkinPath(configSkin);
102
103 if (skinPath.isEmpty()) {
104 skinPath = getSkinPath(getDefaultSkinName());
105 qDebug() << "Could not find the user's configured skin."
106 << "Falling back on the default skin:" << skinPath;
107 }
108 return skinPath;
109 }
110
getDefaultSkinName() const111 QString SkinLoader::getDefaultSkinName() const {
112 return "LateNight";
113 }
114
loadConfiguredSkin(QWidget * pParent,QSet<ControlObject * > * pSkinCreatedControls,KeyboardEventFilter * pKeyboard,PlayerManager * pPlayerManager,ControllerManager * pControllerManager,Library * pLibrary,VinylControlManager * pVCMan,EffectsManager * pEffectsManager,RecordingManager * pRecordingManager)115 QWidget* SkinLoader::loadConfiguredSkin(QWidget* pParent,
116 QSet<ControlObject*>* pSkinCreatedControls,
117 KeyboardEventFilter* pKeyboard,
118 PlayerManager* pPlayerManager,
119 ControllerManager* pControllerManager,
120 Library* pLibrary,
121 VinylControlManager* pVCMan,
122 EffectsManager* pEffectsManager,
123 RecordingManager* pRecordingManager) {
124 ScopedTimer timer("SkinLoader::loadConfiguredSkin");
125 QString skinPath = getConfiguredSkinPath();
126
127 // If we don't have a skin path then fail.
128 if (skinPath.isEmpty()) {
129 return nullptr;
130 }
131
132 LegacySkinParser legacy(m_pConfig,
133 pSkinCreatedControls,
134 pKeyboard,
135 pPlayerManager,
136 pControllerManager,
137 pLibrary,
138 pVCMan,
139 pEffectsManager,
140 pRecordingManager);
141 return legacy.parseSkin(skinPath, pParent);
142 }
143
loadLaunchImage(QWidget * pParent)144 LaunchImage* SkinLoader::loadLaunchImage(QWidget* pParent) {
145 QString skinPath = getConfiguredSkinPath();
146 LegacySkinParser parser(m_pConfig);
147 LaunchImage* pLaunchImage = parser.parseLaunchImage(skinPath, pParent);
148 if (pLaunchImage == nullptr) {
149 // Construct default LaunchImage
150 pLaunchImage = new LaunchImage(pParent, QString());
151 }
152 return pLaunchImage;
153 }
154
pickResizableSkin(const QString & oldSkin) const155 QString SkinLoader::pickResizableSkin(const QString& oldSkin) const {
156 if (oldSkin.contains("latenight", Qt::CaseInsensitive)) {
157 return "LateNight";
158 }
159 if (oldSkin.contains("deere", Qt::CaseInsensitive)) {
160 return "Deere";
161 }
162 if (oldSkin.contains("shade", Qt::CaseInsensitive)) {
163 return "Shade";
164 }
165 return QString();
166 }
167