File indexing completed on 2024-05-12 04:06:27

0001 /*
0002     SPDX-FileCopyrightText: 2011 Stefan Majewsky <majewsky@gmx.net>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "puzzle.h"
0008 
0009 #include <QFileInfo>
0010 #include <QHash>
0011 
0012 //BEGIN Palapeli::PuzzleComponent
0013 
0014 Palapeli::PuzzleComponent::PuzzleComponent()
0015     : m_puzzle(nullptr)
0016 {
0017 }
0018 
0019 Palapeli::PuzzleComponent::~PuzzleComponent()
0020 {
0021 }
0022 
0023 Palapeli::PuzzleComponent* Palapeli::PuzzleComponent::cast(Palapeli::PuzzleComponent::Type type) const
0024 {
0025     Q_UNUSED(type)
0026     return nullptr;
0027 }
0028 
0029 Palapeli::Puzzle* Palapeli::PuzzleComponent::puzzle() const
0030 {
0031     return m_puzzle;
0032 }
0033 
0034 //END Palapeli::PuzzleComponent
0035 //BEGIN Palapeli::Puzzle
0036 
0037 //See Private::get() for the whole story.
0038 struct Component
0039 {
0040     Palapeli::PuzzleComponent *component = nullptr;
0041 
0042     Component() {}
0043     explicit Component(Palapeli::PuzzleComponent* component) : component(component) {}
0044     ~Component() { delete component; }
0045 };
0046 struct Palapeli::Puzzle::Private
0047 {
0048     Palapeli::Puzzle* q;
0049     QHash<Palapeli::PuzzleComponent::Type, Component*> m_components;
0050     Palapeli::PuzzleComponent *m_mainComponent;
0051     QString m_location;
0052     QString m_identifier;
0053 
0054     Private(Palapeli::Puzzle* q, Palapeli::PuzzleComponent* mainComponent, const QString& location, const QString& identifier);
0055     const Palapeli::PuzzleComponent* get(Palapeli::PuzzleComponent::Type type);
0056 };
0057 
0058 Palapeli::Puzzle::Puzzle(Palapeli::PuzzleComponent* mainComponent, const QString& location, const QString& identifier)
0059     : d(new Private(this, mainComponent, location, identifier))
0060 {
0061     qRegisterMetaType<Palapeli::Puzzle*>();
0062 }
0063 
0064 Palapeli::Puzzle::Private::Private(Palapeli::Puzzle* q, Palapeli::PuzzleComponent* mainComponent, const QString& location, const QString& identifier)
0065     : q(q)
0066     , m_mainComponent(mainComponent)
0067     , m_location(location)
0068     , m_identifier(identifier)
0069 {
0070     m_mainComponent->m_puzzle = q;
0071     m_components.insert(mainComponent->type(), new Component(mainComponent));
0072 }
0073 
0074 Palapeli::Puzzle::~Puzzle()
0075 {
0076     QHashIterator<Palapeli::PuzzleComponent::Type, Component*> iter(d->m_components);
0077     while (iter.hasNext())
0078         delete iter.next().value();
0079     delete d;
0080 }
0081 
0082 const Palapeli::PuzzleComponent* Palapeli::Puzzle::component(Palapeli::PuzzleComponent::Type type) const
0083 {
0084     const Component* c = d->m_components.value(type);
0085     return c ? c->component : nullptr;
0086 }
0087 
0088 const Palapeli::PuzzleComponent* Palapeli::Puzzle::get(Palapeli::PuzzleComponent::Type type)
0089 {
0090     return d->get (type);
0091 }
0092 
0093 const Palapeli::PuzzleComponent* Palapeli::Puzzle::Private::get(Palapeli::PuzzleComponent::Type type)
0094 {
0095     Component* c = m_components.value(type);
0096     if (c)
0097         return c->component;
0098 
0099     m_components.insert(type, c = new Component);
0100     Palapeli::PuzzleComponent* cmp = m_mainComponent->cast(type);
0101     if (cmp)
0102         cmp->m_puzzle = q;
0103     c->component = cmp;
0104     return cmp;
0105 }
0106 
0107 QString Palapeli::Puzzle::identifier() const
0108 {
0109     return d->m_identifier;
0110 }
0111 
0112 QString Palapeli::Puzzle::location() const
0113 {
0114     return d->m_location;
0115 }
0116 
0117 void Palapeli::Puzzle::setLocation(const QString& location)
0118 {
0119     d->m_location = location;
0120 }
0121 
0122 void Palapeli::Puzzle::dropComponent(Palapeli::PuzzleComponent::Type type)
0123 {
0124     //DO NEVER EVER USE THIS FUNCTION! THIS FUNCTION IS PURELY DANGEROUS. STUFF WILL BREAK.
0125     Component*& c = d->m_components[type];
0126     delete c;
0127     c = nullptr;
0128 }
0129 
0130 Q_GLOBAL_STATIC(QList<QString>, g_usedIdentifiers)
0131 
0132 /*static*/ QString Palapeli::Puzzle::fsIdentifier(const QString& location)
0133 {
0134     QString puzzleName = QFileInfo(location).fileName();
0135     const char* disallowedChars = "\\:*?\"<>|"; //Windows forbids using these chars in filenames, so we'll strip them
0136     for (const char* c = disallowedChars; *c; ++c)
0137         puzzleName.remove(QLatin1Char(*c));
0138     const QString identifierPattern = QString::fromLatin1("__FSC_%1_%2_").arg(puzzleName);
0139     int uniquifier = 0;
0140     while (g_usedIdentifiers->contains(identifierPattern.arg(uniquifier)))
0141         ++uniquifier;
0142     const QString identifier = identifierPattern.arg(uniquifier);
0143     *g_usedIdentifiers << identifier;
0144     return identifier;
0145 }
0146 
0147 //END Palapeli::Puzzle
0148 
0149 #include "moc_puzzle.cpp"