puzzle.cpp 4.61 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/***************************************************************************
 *   Copyright 2011 Stefan Majewsky <majewsky@gmx.net>
 *
 *   This program is free software; you can redistribute it and/or
 *   modify it under the terms of the GNU General Public
 *   License as published by the Free Software Foundation; either
 *   version 2 of the License, or (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program; if not, write to the Free Software
 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
***************************************************************************/

#include "puzzle.h"

21
22
#include <QFileInfo>
#include <QHash>
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51

//BEGIN Palapeli::PuzzleComponent

Palapeli::PuzzleComponent::PuzzleComponent()
	: m_puzzle(0)
{
}

Palapeli::PuzzleComponent::~PuzzleComponent()
{
}

Palapeli::PuzzleComponent* Palapeli::PuzzleComponent::cast(Palapeli::PuzzleComponent::Type type) const
{
	Q_UNUSED(type)
	return 0;
}

Palapeli::Puzzle* Palapeli::PuzzleComponent::puzzle() const
{
	return m_puzzle;
}

//END Palapeli::PuzzleComponent
//BEGIN Palapeli::Puzzle

//See Private::get() for the whole story.
struct Component
{
52
	Palapeli::PuzzleComponent *component = nullptr;
53

54
55
56
	Component() {}
	explicit Component(Palapeli::PuzzleComponent* component) : component(component) {}
	~Component() { delete component; }
57
58
59
60
61
};
struct Palapeli::Puzzle::Private
{
	Palapeli::Puzzle* q;
	QHash<Palapeli::PuzzleComponent::Type, Component*> m_components;
62
	Palapeli::PuzzleComponent *m_mainComponent;
Stefan Majewsky's avatar
Stefan Majewsky committed
63
	QString m_location;
64
	QString m_identifier;
65

Stefan Majewsky's avatar
Stefan Majewsky committed
66
	Private(Palapeli::Puzzle* q, Palapeli::PuzzleComponent* mainComponent, const QString& location, const QString& identifier);
67
68
69
	const Palapeli::PuzzleComponent* get(Palapeli::PuzzleComponent::Type type);
};

Stefan Majewsky's avatar
Stefan Majewsky committed
70
Palapeli::Puzzle::Puzzle(Palapeli::PuzzleComponent* mainComponent, const QString& location, const QString& identifier)
71
	: d(new Private(this, mainComponent, location, identifier))
72
73
74
75
{
	qRegisterMetaType<Palapeli::Puzzle*>();
}

Stefan Majewsky's avatar
Stefan Majewsky committed
76
Palapeli::Puzzle::Private::Private(Palapeli::Puzzle* q, Palapeli::PuzzleComponent* mainComponent, const QString& location, const QString& identifier)
77
78
	: q(q)
	, m_mainComponent(mainComponent)
79
	, m_location(location)
80
	, m_identifier(identifier)
81
{
82
	m_mainComponent->m_puzzle = q;
83
84
85
86
87
88
89
90
91
92
93
94
95
	m_components.insert(mainComponent->type(), new Component(mainComponent));
}

Palapeli::Puzzle::~Puzzle()
{
	QHashIterator<Palapeli::PuzzleComponent::Type, Component*> iter(d->m_components);
	while (iter.hasNext())
		delete iter.next().value();
	delete d;
}

const Palapeli::PuzzleComponent* Palapeli::Puzzle::component(Palapeli::PuzzleComponent::Type type) const
{
96
97
	const Component* c = d->m_components.value(type);
	return c ? c->component : 0;
98
99
}

100
const Palapeli::PuzzleComponent* Palapeli::Puzzle::get(Palapeli::PuzzleComponent::Type type)
101
{
102
	return d->get (type);
103
104
105
106
}

const Palapeli::PuzzleComponent* Palapeli::Puzzle::Private::get(Palapeli::PuzzleComponent::Type type)
{
107
108
109
110
111
112
113
114
115
116
	Component* c = m_components.value(type);
	if (c)
		return c->component;

	m_components.insert(type, c = new Component);
	Palapeli::PuzzleComponent* cmp = m_mainComponent->cast(type);
	if (cmp)
		cmp->m_puzzle = q;
	c->component = cmp;
	return cmp;
117
118
}

119
120
121
122
123
QString Palapeli::Puzzle::identifier() const
{
	return d->m_identifier;
}

Stefan Majewsky's avatar
Stefan Majewsky committed
124
QString Palapeli::Puzzle::location() const
125
126
127
128
{
	return d->m_location;
}

Stefan Majewsky's avatar
Stefan Majewsky committed
129
void Palapeli::Puzzle::setLocation(const QString& location)
130
131
132
133
{
	d->m_location = location;
}

134
135
136
137
138
139
140
141
void Palapeli::Puzzle::dropComponent(Palapeli::PuzzleComponent::Type type)
{
	//DO NEVER EVER USE THIS FUNCTION! THIS FUNCTION IS PURELY DANGEROUS. STUFF WILL BREAK.
	Component*& c = d->m_components[type];
	delete c;
	c = 0;
}

Laurent Montel's avatar
Laurent Montel committed
142
Q_GLOBAL_STATIC(QList<QString>, g_usedIdentifiers)
143

Stefan Majewsky's avatar
Stefan Majewsky committed
144
/*static*/ QString Palapeli::Puzzle::fsIdentifier(const QString& location)
145
{
Stefan Majewsky's avatar
Stefan Majewsky committed
146
	QString puzzleName = QFileInfo(location).fileName();
147
148
149
150
151
152
153
154
155
156
157
158
	const char* disallowedChars = "\\:*?\"<>|"; //Windows forbids using these chars in filenames, so we'll strip them
	for (const char* c = disallowedChars; *c; ++c)
		puzzleName.remove(*c);
	const QString identifierPattern = QString::fromLatin1("__FSC_%1_%2_").arg(puzzleName);
	int uniquifier = 0;
	while (g_usedIdentifiers->contains(identifierPattern.arg(uniquifier)))
		++uniquifier;
	const QString identifier = identifierPattern.arg(uniquifier);
	*g_usedIdentifiers << identifier;
	return identifier;
}

159
160
//END Palapeli::Puzzle