Warning, file /graphics/kxstitch/src/SchemeManager.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 * Copyright (C) 2010-2015 by Stephen Allewell 0003 * steve.allewell@gmail.com 0004 * 0005 * This program is free software; you can redistribute it and/or modify 0006 * it under the terms of the GNU General Public License as published by 0007 * the Free Software Foundation; either version 2 of the License, or 0008 * (at your option) any later version. 0009 */ 0010 0011 #include "SchemeManager.h" 0012 0013 #include <QDir> 0014 #include <QDirIterator> 0015 #include <QFile> 0016 #include <QFileInfo> 0017 #include <QStandardPaths> 0018 #include <QUrl> 0019 #include <QXmlInputSource> 0020 #include <QXmlSimpleReader> 0021 0022 #include <KLocalizedString> 0023 #include <KMessageBox> 0024 0025 #include "Floss.h" 0026 #include "FlossScheme.h" 0027 #include "SchemeParser.h" 0028 0029 SchemeManager *SchemeManager::schemeManager = nullptr; 0030 0031 /** 0032 Accessor for the static object 0033 */ 0034 SchemeManager &SchemeManager::self() 0035 { 0036 if (schemeManager == nullptr) { 0037 schemeManager = new SchemeManager(); 0038 } 0039 0040 return *schemeManager; 0041 } 0042 0043 /** 0044 Constructor. 0045 */ 0046 SchemeManager::SchemeManager() 0047 : QObject() 0048 { 0049 /** Refresh the list of floss schemes. */ 0050 refresh(); 0051 } 0052 0053 /** 0054 Destructor. Delete all the floss schemes. 0055 */ 0056 SchemeManager::~SchemeManager() 0057 { 0058 qDeleteAll(m_flossSchemes); 0059 } 0060 0061 /** 0062 Create a new scheme. The name is checked to see if it already exists, if not a new instance of a FlossScheme 0063 is created. 0064 @param schemeName the name of the scheme to be created. 0065 @return a pointer to the new FlossScheme instance, null if it already exists or a new one could not be created. 0066 */ 0067 FlossScheme *SchemeManager::createScheme(QString schemeName) 0068 { 0069 FlossScheme *flossScheme = nullptr; 0070 0071 if (scheme(schemeName) == nullptr) { 0072 if ((flossScheme = new FlossScheme)) { 0073 flossScheme->setSchemeName(schemeName); 0074 self().m_flossSchemes.append(flossScheme); 0075 } 0076 } 0077 0078 return flossScheme; 0079 } 0080 0081 /** 0082 Get a list of the FlossSchemes available. 0083 @return QStringList of scheme names. 0084 */ 0085 QStringList SchemeManager::schemes() 0086 { 0087 QStringList schemeNames; 0088 0089 QListIterator<FlossScheme *> i(self().m_flossSchemes); 0090 0091 while (i.hasNext()) { 0092 schemeNames.append(i.next()->schemeName()); 0093 } 0094 0095 return schemeNames; 0096 } 0097 0098 /** 0099 Get a pointer to a scheme by name 0100 @param name of the scheme required. 0101 @return pointer to the FlossScheme instance, returns null if no scheme found. 0102 */ 0103 FlossScheme *SchemeManager::scheme(QString name) 0104 { 0105 FlossScheme *flossScheme; 0106 0107 QListIterator<FlossScheme *> i(self().m_flossSchemes); 0108 0109 while (i.hasNext()) { 0110 flossScheme = i.next(); 0111 0112 if (flossScheme->schemeName() == name) { 0113 return flossScheme; 0114 } 0115 } 0116 0117 return nullptr; 0118 } 0119 0120 /** 0121 Read a scheme. 0122 @param name path to the xml file to be read. 0123 @return pointer to the FlossScheme instance created. 0124 */ 0125 FlossScheme *SchemeManager::readScheme(QString name) 0126 { 0127 SchemeParser handler; 0128 QFile xmlFile(name); 0129 QXmlInputSource source(&xmlFile); 0130 QXmlSimpleReader reader; 0131 reader.setContentHandler(&handler); 0132 0133 bool success = reader.parse(source); 0134 0135 if (!success) { 0136 KMessageBox::error(nullptr, i18n("Error reading scheme %1\n%2.", name, handler.errorString()), i18n("Error reading floss scheme.")); 0137 } 0138 0139 FlossScheme *flossScheme = handler.flossScheme(); 0140 0141 if (!success) { 0142 delete flossScheme; 0143 flossScheme = nullptr; 0144 } else { 0145 flossScheme->setPath(name); 0146 } 0147 0148 return flossScheme; 0149 } 0150 0151 /** 0152 Save a modified scheme to a writable location. 0153 @param name of the scheme to be saved. 0154 @return true if the scheme was successfully saved, false otherwise. 0155 */ 0156 bool SchemeManager::writeScheme(QString name) 0157 { 0158 FlossScheme *flossScheme = scheme(name); 0159 QFileInfo fileInfo(flossScheme->path()); 0160 0161 if (!fileInfo.isWritable()) { 0162 QString writableDir = QStandardPaths::writableLocation(QStandardPaths::DataLocation); // this may be empty or may not exist 0163 0164 if (writableDir.isEmpty()) { 0165 KMessageBox::error(nullptr, i18n("Unable to locate a writable directory\nto store the scheme.")); 0166 return false; 0167 // TODO Allow user to select a location to store the calibrated schemes 0168 } 0169 0170 writableDir += QLatin1String("/schemes/"); 0171 0172 if (!QDir(writableDir).exists()) { 0173 if (!QDir().mkpath(writableDir)) { 0174 KMessageBox::error(nullptr, i18n("Unable to locate a writable directory\nto store the scheme.")); 0175 return false; 0176 // TODO Allow user to select a location to store the calibrated schemes 0177 } 0178 } 0179 0180 // at this point a writable directory should be in writableDir 0181 0182 QString writablePath = writableDir + fileInfo.fileName(); 0183 fileInfo.setFile(writablePath); 0184 } 0185 0186 QFile schemeFile(fileInfo.filePath()); 0187 0188 if (schemeFile.open(QIODevice::WriteOnly)) { 0189 QTextStream stream(&schemeFile); 0190 stream << "<!DOCTYPE flossScheme SYSTEM \"flossScheme.dtd\">\n<flossScheme>\n"; 0191 stream << "<title>" << name.replace(QLatin1Char('&'), QLatin1String("&")) << "</title>\n"; // includes fixup for the J&P Coates scheme 0192 QListIterator<Floss *> it(flossScheme->flosses()); 0193 0194 while (it.hasNext()) { 0195 Floss *floss = it.next(); 0196 stream << "<floss><name>" << floss->name() << "</name><description>" << floss->description() << "</description>"; 0197 stream << "<color><red>" << floss->color().red() << "</red><green>" << floss->color().green() << "</green><blue>" << floss->color().blue() 0198 << "</blue></color></floss>\n"; 0199 } 0200 0201 stream << "</flossScheme>\n"; 0202 schemeFile.close(); 0203 0204 return true; 0205 } 0206 0207 return false; 0208 } 0209 0210 /** 0211 Get a list of files that contain xml schemes, iterating each one to create a new FlossScheme instance 0212 and read the scheme. Each path found is added to the KDirWatch instance to allow automatic reload of scheme 0213 data if it is changed outside of KXStitch. 0214 Assumes that local resources are given before global ones and should take priority. 0215 */ 0216 void SchemeManager::refresh() 0217 { 0218 const QStringList dirs = QStandardPaths::locateAll(QStandardPaths::DataLocation, QStringLiteral("schemes"), QStandardPaths::LocateDirectory); 0219 0220 Q_FOREACH (const QString &dir, dirs) { 0221 QDirIterator it(dir, QStringList() << QLatin1String("*.xml")); 0222 0223 while (it.hasNext()) { 0224 FlossScheme *flossScheme = readScheme(it.next()); 0225 0226 if (flossScheme) { 0227 for (int i = 0; i < m_flossSchemes.count(); ++i) { 0228 if (m_flossSchemes.at(i)->schemeName() == flossScheme->schemeName()) { 0229 delete flossScheme; 0230 flossScheme = nullptr; 0231 break; 0232 } 0233 } 0234 0235 if (flossScheme) { 0236 m_flossSchemes.append(flossScheme); 0237 } 0238 } 0239 } 0240 } 0241 } 0242 0243 #include "moc_SchemeManager.cpp"