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