3 * \file LayoutModuleList.cpp
4 * This file is part of LyX, the document processor.
5 * Licence details can be found in the file COPYING.
7 * \author Richard Kimberly Heck
9 * Full author contact details are available in file CREDITS.
14 #include "LayoutModuleList.h"
16 #include "LayoutFile.h"
17 #include "ModuleList.h"
19 #include "support/debug.h"
30 // the previous document class may have loaded some modules that the
31 // new one excludes, and the new class may provide, etc, some that
32 // conflict with ones that were already loaded. So we need to go
33 // through the list and fix everything. I suppose there are various
34 // ways this could be done, but the following seems to work at the
35 // moment. (Thanks to Philippe Charpentier for helping work out all
37 bool LayoutModuleList::adaptToBaseClass(LayoutFile const * const lay,
38 std::list<string> const & removedModules)
40 // first, we remove any modules the new document class itself provides,
41 // those it excludes, and those that conflict with ones it excludes.
42 // this has to be done first because, otherwise, a module we're about
43 // to remove could prevent a default module from being added.
44 bool retval = removeBadModules(lay);
45 // next, we add any default modules the new class provides.
46 addDefaultModules(lay, removedModules);
47 // finally, we perform a general consistency check on the set of
48 // loaded modules. it's a hassle that we have to do this now, since
49 // we just went through them a bit ago, but things might have changed
50 // with the loading of the default modules.
51 retval = (checkModuleConsistency(lay) || retval);
56 string LayoutModuleList::asString() const
59 for (auto const & mod : lml_)
61 // remove trailing comma
68 bool LayoutModuleList::moduleCanBeAdded(string const & modName,
69 LayoutFile const * const lay) const
71 // Is the module already present?
72 const_iterator it = begin();
73 const_iterator const en = end();
74 for (; it != en; ++it)
78 LyXModule const * const lm = theModuleList[modName];
82 // Does this module conflict with the document class or any loaded modules?
83 if (moduleConflicts(modName, lay))
86 // Is this module already provided by the document class?
87 const_iterator const provmodstart = lay->providedModules().begin();
88 const_iterator const provmodend = lay->providedModules().end();
89 if (find(provmodstart, provmodend, modName) != provmodend)
92 // Check whether some required module is available
93 vector<string> const reqs = lm->getRequiredModules();
97 const_iterator mit = begin();
98 const_iterator const men = end();
99 vector<string>::const_iterator rit = reqs.begin();
100 vector<string>::const_iterator ren = reqs.end();
101 bool foundone = false;
102 for (; rit != ren; ++rit) {
103 if (find(mit, men, *rit) != men ||
104 find(provmodstart, provmodend, *rit) != provmodend) {
114 bool LayoutModuleList::moduleConflicts(string const & modName,
115 LayoutFile const * const lay) const
117 // Is this module explicitly excluded by the document class?
118 const_iterator const exclmodstart = lay->excludedModules().begin();
119 const_iterator const exclmodend = lay->excludedModules().end();
120 if (find(exclmodstart, exclmodend, modName) != exclmodend)
122 // Check for conflicts with used modules
123 // first the provided modules...
124 const_iterator provmodit = lay->providedModules().begin();
125 const_iterator const provmodend = lay->providedModules().end();
126 for (; provmodit != provmodend; ++provmodit) {
127 if (!LyXModule::areCompatible(modName, *provmodit))
130 // and then the selected modules
131 const_iterator mit = begin();
132 const_iterator const men = end();
133 for (; mit != men; ++mit)
134 if (!LyXModule::areCompatible(modName, *mit))
140 void LayoutModuleList::addDefaultModules(LayoutFile const * const lay,
141 std::list<string> removedModules)
143 LayoutModuleList mods = lay->defaultModules();
144 const_iterator mit = mods.begin();
145 const_iterator const men = mods.end();
147 // We want to insert the default modules at the beginning of
148 // the list, but also to insert them in the correct order.
149 // The obvious thing to do would be to collect them and then
150 // insert them, but that doesn't work because a later default
151 // module may require an earlier one, and then the test below
152 // moduleCanBeAdded(modname)
153 // will fail. So we have to do it a more complicated way.
154 iterator insertpos = begin();
157 for (; mit != men; ++mit) {
158 string const & modName = *mit;
159 // make sure the user hasn't removed it
160 if (find(removedModules.begin(), removedModules.end(), modName) !=
161 removedModules.end()) {
162 LYXERR(Debug::TCLASS, "Default module `" << modName <<
163 "' not added because removed by user.");
167 if (!moduleCanBeAdded(modName, lay)) {
168 // FIXME This could be because it's already present, so we should
169 // probably return something indicating that.
170 LYXERR(Debug::TCLASS, "Default module `" << modName <<
171 "' could not be added.");
174 LYXERR(Debug::TCLASS, "Default module `" << modName << "' added.");
175 insert(insertpos, modName);
176 // now we reset insertpos
179 advance(insertpos, numinserts);
184 bool LayoutModuleList::removeBadModules(LayoutFile const * const lay)
186 // we'll write a new list of modules, since we can't just remove them,
187 // as that would invalidate our iterators
188 LayoutModuleList oldModules = *this;
191 LayoutModuleList const & provmods = lay->providedModules();
192 LayoutModuleList const & exclmods = lay->excludedModules();
193 bool consistent = true; // set to false if we have to do anything
195 const_iterator oit = oldModules.begin();
196 const_iterator const oen = oldModules.end();
197 for (; oit != oen; ++oit) {
198 string const & modname = *oit;
199 // skip modules that the class provides
200 if (find(provmods.begin(), provmods.end(), modname) != provmods.end()) {
201 LYXERR0("Module `" << modname << "' dropped because provided by document class.");
205 // are we excluded by the document class?
206 if (find(exclmods.begin(), exclmods.end(), modname) != exclmods.end()) {
207 LYXERR0("Module `" << modname << "' dropped because excluded by document class.");
211 // determine whether some provided module excludes us or we exclude it
212 const_iterator pit = provmods.begin();
213 const_iterator const pen = provmods.end();
214 bool excluded = false;
215 for (; !excluded && pit != pen; ++pit) {
216 if (!LyXModule::areCompatible(modname, *pit)) {
217 LYXERR0("Module " << modname <<
218 " dropped because it conflicts with provided module `" << *pit << "'.");
231 // Perform a consistency check on the set of modules. We need to make
232 // sure that none of the modules exclude each other and that requires
234 bool LayoutModuleList::checkModuleConsistency(LayoutFile const * const lay)
236 bool consistent = true;
237 LayoutModuleList oldModules = *this;
239 const_iterator oit = oldModules.begin();
240 const_iterator const oen = oldModules.end();
241 LayoutModuleList const & provmods = lay->providedModules();
242 for (; oit != oen; ++oit) {
243 string const & modname = *oit;
244 bool excluded = false;
245 // Determine whether some prior module excludes us, or we exclude it
246 const_iterator lit = begin();
247 const_iterator const len = end();
248 for (; !excluded && lit != len; ++lit) {
249 if (!LyXModule::areCompatible(modname, *lit)) {
251 LYXERR0("Module " << modname <<
252 " dropped because it is excluded by prior module " << *lit);
260 // determine whether some provided module or some prior module
261 // satisfies our requirements
262 LyXModule const * const oldmod = theModuleList[modname];
264 LYXERR0("Default module " << modname <<
265 " added although it is unavailable and can't check requirements.");
269 vector<string> const & reqs = oldmod->getRequiredModules();
271 // we now set excluded to true, meaning that we haven't
272 // yet found a required module.
274 vector<string>::const_iterator rit = reqs.begin();
275 vector<string>::const_iterator const ren = reqs.end();
276 for (; rit != ren; ++rit) {
277 string const reqmod = *rit;
278 if (find(provmods.begin(), provmods.end(), reqmod) !=
283 if (find(begin(), end(), reqmod) != end()) {
291 LYXERR0("Module " << modname << " dropped because requirements not met.");
293 LYXERR(Debug::TCLASS, "Module " << modname << " passed consistency check.");