1 /*
2 * Copyright (C) 2010-2015 by Stephen Allewell
3 * steve.allewell@gmail.com
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 */
10
11
12 /**
13 * @file
14 * Implement the SymbolManager class. This loads all symbol libraries from the kxstitch application
15 * data folders and allows the selection of a library by name. The manager is implemented as a
16 * singleton class accessible from anywhere in the application. Symbols need to be available to the
17 * palette manager and from the renderer.
18 */
19
20
21 /**
22 * @page symbol_manager Symbol Manager
23 * The symbol manager provides an interface between the application and the collection of symbol sets.
24 * A number of symbol libraries can exist and a particular set can be selected in the palette manager
25 * symbol selector.
26 */
27
28
29 #include "SymbolManager.h"
30
31 #include <QDir>
32 #include <QDirIterator>
33 #include <QFile>
34 #include <QStandardPaths>
35 #include <QUrl>
36
37 #include <KLocalizedString>
38 #include <KMessageBox>
39
40 #include "Exceptions.h"
41 #include "Symbol.h"
42 #include "SymbolLibrary.h"
43
44
45 SymbolManager *SymbolManager::symbolManager = nullptr;
46
47
48 /**
49 * Accessor for the static object
50 */
self()51 SymbolManager &SymbolManager::self()
52 {
53 if (symbolManager == nullptr) {
54 symbolManager = new SymbolManager();
55 }
56
57 return *symbolManager;
58 }
59
60
61 /**
62 * Constructor.
63 */
SymbolManager()64 SymbolManager::SymbolManager()
65 {
66 refresh();
67 }
68
69
70 /**
71 *Destructor. Delete all the symbol libraries.
72 */
~SymbolManager()73 SymbolManager::~SymbolManager()
74 {
75 qDeleteAll(m_symbolLibraries);
76 }
77
78
79 /**
80 * Get a list of the symbol libraries available.
81 *
82 * @return QStringList of symbol library names.
83 */
libraries()84 QStringList SymbolManager::libraries()
85 {
86 QStringList libraryNames;
87
88 QListIterator<SymbolLibrary *> i(self().m_symbolLibraries);
89
90 while (i.hasNext()) {
91 libraryNames.append(i.next()->name());
92 }
93
94 return libraryNames;
95 }
96
97
98 /**
99 * Get a pointer to a symbol library by name
100 *
101 * @param name of the library required.
102 *
103 * @return pointer to the SymbolLibrary instance, returns null if no library found.
104 */
library(const QString & name)105 SymbolLibrary *SymbolManager::library(const QString &name)
106 {
107 for (int i = 0 ; i < self().m_symbolLibraries.count() ; ++i) {
108 SymbolLibrary *symbolLibrary = self().m_symbolLibraries.at(i);
109
110 if (symbolLibrary->name() == name) {
111 return symbolLibrary;
112 }
113 }
114
115 return nullptr;
116 }
117
118
119 /**
120 * Get a list of files stored in the symbols path, iterating each one to create a new SymbolLibrary instance
121 * and read the library.
122 * Assumes that local resources are given before global ones and should take priority.
123 */
refresh()124 void SymbolManager::refresh()
125 {
126 const QStringList dirs = QStandardPaths::locateAll(QStandardPaths::DataLocation, QStringLiteral("symbols"), QStandardPaths::LocateDirectory);
127
128 Q_FOREACH (const QString &dir, dirs) {
129 QDirIterator it(dir, QStringList() << QStringLiteral("*.sym"));
130
131 while (it.hasNext()) {
132 SymbolLibrary *symbolLibrary = readLibrary(it.next());
133
134 if (symbolLibrary) {
135 m_symbolLibraries.append(symbolLibrary);
136 }
137 }
138 }
139 }
140
141
142 /**
143 * Read a symbol library.
144 *
145 * @param name path to the symbol file to be read.
146 *
147 * @return pointer to the SymbolLibrary instance created.
148 */
readLibrary(const QString & name)149 SymbolLibrary *SymbolManager::readLibrary(const QString &name)
150 {
151 SymbolLibrary *symbolLibrary = new SymbolLibrary;
152
153 QFile file(name);
154
155 if (file.open(QIODevice::ReadOnly)) {
156 QDataStream stream(&file);
157
158 try {
159 stream >> *symbolLibrary;
160 symbolLibrary->setName(QFileInfo(name).baseName());
161 } catch (const InvalidFile &e) {
162 KMessageBox::sorry(nullptr, i18n("This does not appear to be a valid symbol file"));
163 delete symbolLibrary;
164 symbolLibrary = nullptr;
165 } catch (const InvalidFileVersion &e) {
166 KMessageBox::sorry(nullptr, e.version);
167 delete symbolLibrary;
168 symbolLibrary = nullptr;
169 } catch (const FailedReadFile &e) {
170 KMessageBox::sorry(nullptr, e.status);
171 delete symbolLibrary;
172 symbolLibrary = nullptr;
173 }
174
175 file.close();
176 } else {
177 KMessageBox::sorry(nullptr, i18n("Failed to open the file %1", name));
178 delete symbolLibrary;
179 symbolLibrary = nullptr;
180 }
181
182 return symbolLibrary;
183 }
184