BuildmLearn Toolkit  2.0.4
BuildmLearn Toolkit is an easy-to-use program that helps users make mobile apps without any knowledge of application development.
 All Classes Functions Enumerations Groups Pages
templatefactory.cpp
1 /*
2  Copyright (c) 2012, BuildmLearn Contributors listed at http://buildmlearn.org/people/
3  All rights reserved.
4 
5  Redistribution and use in source and binary forms, with or without
6  modification, are permitted provided that the following conditions are met:
7 
8  * Redistributions of source code must retain the above copyright notice, this
9  list of conditions and the following disclaimer.
10 
11  * Redistributions in binary form must reproduce the above copyright notice,
12  this list of conditions and the following disclaimer in the documentation
13  and/or other materials provided with the distribution.
14 
15  * Neither the name of the BuildmLearn nor the names of its
16  contributors may be used to endorse or promote products derived from
17  this software without specific prior written permission.
18 
19  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30 
31 #include "core/templatefactory.h"
32 
33 #include "definitions/definitions.h"
34 #include "core/templatecore.h"
35 #include "core/templateeditor.h"
36 #include "core/templateentrypoint.h"
37 #include "core/templategenerator.h"
38 #include "miscellaneous/settings.h"
39 #include "miscellaneous/application.h"
40 #include "templates/quiz/quizentrypoint.h"
41 #include "templates/flashcard/flashcardentrypoint.h"
42 #include "templates/mlearning/basicmlearningentrypoint.h"
43 #include "templates/learnspellings/learnspellingsentrypoint.h"
44 
45 #if QT_VERSION >= 0x050000
46 #include <QStandardPaths>
47 #else
48 #include <QDesktopServices>
49 #endif
50 
51 #include <QDateTime>
52 #include <QFile>
53 #include <QTextStream>
54 
55 
56 TemplateFactory::TemplateFactory(QObject *parent)
57  : QObject(parent), m_availableTemplates(QHash<QString, TemplateEntryPoint*>()),
58  m_activeEntryPoint(NULL), m_activeCore(NULL),
59  m_generator(new TemplateGenerator(this)) {
60  setupTemplates();
61 }
62 
63 TemplateFactory::~TemplateFactory() {
64  qDebug("Destroying TemplateFactory instance.");
65 }
66 
67 QList<TemplateEntryPoint*> TemplateFactory::availableTemplates() {
68  QList<TemplateEntryPoint*> entries;
69 
70  foreach (TemplateEntryPoint *entry, m_availableTemplates.values()) {
71  for (int i = 0; i <= entries.size(); i++) {
72  if (i == entries.size()) {
73  entries.append(entry);
74  break;
75  }
76  else if (entry->humanName() < entries.at(i)->humanName()) {
77  entries.insert(i, entry);
78  break;
79  }
80  }
81  }
82 
83  return entries;
84 }
85 
87 #if QT_VERSION >= 0x050000
88  return qApp->settings()->value(APP_CFG_TEMPLATES, "temp_directory",
89  QStandardPaths::writableLocation(QStandardPaths::TempLocation)).toString();
90 #else
91  return qApp->settings()->value(APP_CFG_TEMPLATES, "temp_directory",
92  QDesktopServices::storageLocation(QDesktopServices::TempLocation)).toString();
93 #endif
94 }
95 
96 void TemplateFactory::setTempDirectory(const QString &temp_directory) {
97  qApp->settings()->setValue(APP_CFG_TEMPLATES, "temp_directory", temp_directory);
98 }
99 
101 #if QT_VERSION >= 0x050000
102  return qApp->settings()->value(APP_CFG_TEMPLATES, "output_directory",
103  QStandardPaths::writableLocation(QStandardPaths::DesktopLocation)).toString();
104 #else
105  return qApp->settings()->value(APP_CFG_TEMPLATES, "output_directory",
106  QDesktopServices::storageLocation(QDesktopServices::DesktopLocation)).toString();
107 #endif
108 }
109 
110 void TemplateFactory::setOutputDirectory(const QString &output_directory) {
111  qApp->settings()->setValue(APP_CFG_TEMPLATES, "output_directory", output_directory);
112 }
113 
115  return qApp->settings()->value(APP_CFG_TEMPLATES, "application_file_name_pattern",
116  "application-%1-%2-%3.apk").toString();
117 }
118 
119 void TemplateFactory::setApplicationFileNamePattern(const QString &file_name_pattern) {
120  qApp->settings()->setValue(APP_CFG_TEMPLATES, "application_file_name_pattern", file_name_pattern);
121 }
122 
123 QString TemplateFactory::applicationFileName(const QString &project_name) {
124  if (activeEntryPoint() != NULL) {
125  return applicationFileNamePattern().arg(activeEntryPoint()->name(),
126  project_name,
127  QDateTime::currentDateTime().toString("yyyyMMddThhmmss"));
128  }
129  else {
130  return QString();
131  }
132 }
133 
134 QDomDocument TemplateFactory::generateBundleHeader(const QString &template_type, const QString &author_name, const QString &author_email, const QString &project_title, const QString &project_description, const QString &template_version) {
135  QDomDocument xml_bundle;
136  QDomElement root_element = xml_bundle.createElement("buildmlearn_application");
137  QDomElement author_element = xml_bundle.createElement("author");
138  QDomElement name_element = xml_bundle.createElement("name");
139  QDomElement email_element = xml_bundle.createElement("email");
140  QDomElement title_element = xml_bundle.createElement("title");
141  QDomElement description_element = xml_bundle.createElement("description");
142  QDomElement version_element = xml_bundle.createElement("version");
143  QDomElement data_element = xml_bundle.createElement("data");
144 
145 
146  root_element.setAttribute("type", template_type);
147  name_element.appendChild(xml_bundle.createTextNode(author_name));
148  email_element.appendChild(xml_bundle.createTextNode(author_email));
149  title_element.appendChild(xml_bundle.createTextNode(project_title));
150  description_element.appendChild(xml_bundle.createTextNode(project_description));
151  version_element.appendChild(xml_bundle.createTextNode(template_version));
152 
153  author_element.appendChild(name_element);
154  author_element.appendChild(email_element);
155 
156  root_element.appendChild(author_element);
157  root_element.appendChild(title_element);
158  root_element.appendChild(description_element);
159  root_element.appendChild(version_element);
160  root_element.appendChild(data_element);
161 
162  xml_bundle.appendChild(root_element);
163 
164  return xml_bundle;
165 }
166 
168  return s1->humanName() < s2.humanName();
169 }
170 
172 }
173 
174 void TemplateFactory::clearEntryAndCore() {
175  if (m_activeEntryPoint != NULL) {
176  m_activeEntryPoint = NULL;
177  }
178 
179  if (m_activeCore != NULL) {
180  m_activeCore->deleteLater();
181  m_activeCore = NULL;
182  }
183 }
184 
186  // Start new project with selected template entry point.
187  clearEntryAndCore();
188 
189  m_activeEntryPoint = entry_point;
190  m_activeCore = entry_point->createNewCore();
191 
192  emit newTemplateCoreCreated(m_activeCore);
193 
194  return true;
195 }
196 
197 bool TemplateFactory::loadProject(const QString &bundle_file_name) {
198  // TODO: Load project from XML bundle file.
199  // Detect which template is it, then start new project with that template
200  // and fill data in.
201 
202  QFile bundle_file(bundle_file_name);
203 
204  if (!bundle_file.open(QIODevice::Text | QIODevice::ReadOnly | QIODevice::Unbuffered)) {
205  qApp->trayIcon()->showMessage(tr("Cannot load XML bundle"),
206  tr("Bundle cannot be loaded because XML file cannot be opened for reading."),
207  QSystemTrayIcon::Critical);
208 
209  return false;
210  }
211 
212  // Bundle file is opened, read its contents and determine which template entry point
213  // it belongs to.
214  QString bundle_data(bundle_file.readAll());
215  bundle_file.close();
216 
217  TemplateEntryPoint *target_entry_point = entryPointForBundle(bundle_data);
218 
219  if (target_entry_point == NULL) {
220  qApp->trayIcon()->showMessage(tr("Cannot load XML bundle"),
221  tr("Bundle cannot be loaded because XML file is corrupted."),
222  QSystemTrayIcon::Critical);
223 
224  return false;
225  }
226 
227  TemplateCore *loaded_core = target_entry_point->loadCoreFromBundleData(bundle_data);
228 
229  if (loaded_core == NULL) {
230  qApp->trayIcon()->showMessage(tr("Cannot load XML bundle"),
231  tr("Target template was not able to load XML bundle data."),
232  QSystemTrayIcon::Critical);
233 
234  return false;
235  }
236 
237  // Clear previous data and start loaded core.
238  clearEntryAndCore();
239  loaded_core->setAssignedFile(bundle_file_name);
240  loaded_core->editor()->setIsDirty(false);
241 
242  m_activeEntryPoint = target_entry_point;
243  m_activeCore = loaded_core;
244 
245  emit newTemplateCoreCreated(m_activeCore);
246 
247  return true;
248 }
249 
251  if (bundle_data.isEmpty()) {
252  return NULL;
253  }
254 
255  QDomDocument xml_document;
256  xml_document.setContent(bundle_data);
257 
258  return m_availableTemplates.value(xml_document.documentElement().attribute("type"), NULL);
259 }
260 
261 bool TemplateFactory::saveCurrentProjectAs(const QString &bundle_file_name) {
262  // TODO: Save current project to given file.
263 
264  QString xml_bundle_contents = activeCore()->editor()->generateBundleData();
265 
266  if (xml_bundle_contents.isEmpty()) {
267  // There is nothing to save. This is quite problem.
268  qWarning("There is nothing to save for template \"%s\".", qPrintable(activeCore()->entryPoint()->humanName()));
269  return false;
270  }
271 
272  QFile target_xml_file(bundle_file_name);
273 
274  if (target_xml_file.open(QIODevice::Truncate | QIODevice::WriteOnly |
275  QIODevice::Unbuffered | QIODevice::Text)) {
276  QTextStream stream(&target_xml_file);
277 
278  stream << xml_bundle_contents;
279  stream.flush();
280 
281  target_xml_file.flush();
282  target_xml_file.close();
283 
284  activeCore()->setAssignedFile(bundle_file_name);
285  activeCore()->editor()->setIsDirty(false);
286 
287  return true;
288  }
289  else {
290  return false;
291  }
292 }
293 
295  if (activeCore() == NULL || activeCore()->assignedFile().isEmpty()) {
296  return false;
297  }
298  else {
299  return saveCurrentProjectAs(activeCore()->assignedFile());
300  }
301 }
302 
303 void TemplateFactory::setupTemplates() {
304  // TODO: Fill in needed template entry points.
305  TemplateEntryPoint *flashcard_entry = new FlashCardEntryPoint(this);
306  m_availableTemplates.insert(flashcard_entry->typeIndentifier(), flashcard_entry);
307 
308  TemplateEntryPoint *info_entry = new BasicmLearningEntryPoint(this);
309  m_availableTemplates.insert(info_entry->typeIndentifier(), info_entry);
310 
311  TemplateEntryPoint *quiz_entry = new QuizEntryPoint(this);
312  m_availableTemplates.insert(quiz_entry->typeIndentifier(), quiz_entry);
313 
314  TemplateEntryPoint *learnspellings_entry = new LearnSpellingsEntryPoint(this);
315  m_availableTemplates.insert(learnspellings_entry->typeIndentifier(), learnspellings_entry);
316 }
317 
319  return m_generator;
320 }
QString typeIndentifier() const
Identifier of the template.
TemplateEntryPoint * entryPointForBundle(const QString &bundle_data)
Decides which entry point raw XML bundle data belong to.
void newTemplateCoreCreated(TemplateCore *core)
Emitted if new project using some template core is started.
QString applicationFileName(const QString &project_name)
Generates file name for output APK file.
static bool entryPointIsLessThan(TemplateEntryPoint *s1, TemplateEntryPoint &s2)
Performs lexicographical comparison of two entry points.
TemplateGenerator * generator() const
Access to component which supervises generating of APK files.
virtual TemplateEditor * editor() const
Access to editor widget of the template.
Definition: templatecore.h:84
bool saveCurrentProject()
Saves current project to assigned file if there is any.
QString outputDirectory() const
Access to directory used throughout APK generation process.
QDomDocument generateBundleHeader(const QString &template_type, const QString &author_name, const QString &author_email, const QString &project_title, const QString &project_description, const QString &template_version)
Generates common XML bundle.
QString applicationFileNamePattern() const
Access to pattern used for name of output APK file.
Entry point of Learn Spellings template.
virtual TemplateCore * createNewCore()=0
Creates new instance of template core.
TemplateCore * activeCore() const
Access to active core.
bool startNewProject(TemplateEntryPoint *entry_point)
Starts new project core from given entry point.
void setAssignedFile(const QString &assigned_file)
Sets new assigned file.
virtual TemplateCore * loadCoreFromBundleData(const QString &raw_data)=0
Creates new instance and fills it template-specific data ("load project" functionality).
bool loadProject(const QString &bundle_file_name)
Loads stored project and initializes new core according to it.
Entry point.
TemplateEntryPoint * activeEntryPoint() const
Access to active entry point.
virtual QString humanName() const
Human-readable name of template.
bool saveCurrentProjectAs(const QString &bundle_file_name)
Saves current project to given file.
QList< TemplateEntryPoint * > availableTemplates()
Access to available templates.
Generator responsible for generating APK mobile applications.
void quit()
Quits running actions of template manager.
The entry point for a template.
void setIsDirty(bool is_dirty)
Sets new dirtiness status.
The core class container for single template.
Definition: templatecore.h:43
virtual QString generateBundleData()=0
Generates RAW data which represent data of this template.
QString tempDirectory() const
Access to temporary directory used throughout APK generation process.