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 bool LayoutModuleList::moduleCanBeAdded(string const & modName,
57 LayoutFile const * const lay) const
59 // Is the module already present?
60 const_iterator it = begin();
61 const_iterator const en = end();
62 for (; it != en; ++it)
66 LyXModule const * const lm = theModuleList[modName];
70 // Does this module conflict with the document class or any loaded modules?
71 if (moduleConflicts(modName, lay))
74 // Is this module already provided by the document class?
75 const_iterator const provmodstart = lay->providedModules().begin();
76 const_iterator const provmodend = lay->providedModules().end();
77 if (find(provmodstart, provmodend, modName) != provmodend)
80 // Check whether some required module is available
81 vector<string> const reqs = lm->getRequiredModules();
85 const_iterator mit = begin();
86 const_iterator const men = end();
87 vector<string>::const_iterator rit = reqs.begin();
88 vector<string>::const_iterator ren = reqs.end();
89 bool foundone = false;
90 for (; rit != ren; ++rit) {
91 if (find(mit, men, *rit) != men ||
92 find(provmodstart, provmodend, *rit) != provmodend) {
102 bool LayoutModuleList::moduleConflicts(string const & modName,
103 LayoutFile const * const lay) const
105 // Is this module explicitly excluded by the document class?
106 const_iterator const exclmodstart = lay->excludedModules().begin();
107 const_iterator const exclmodend = lay->excludedModules().end();
108 if (find(exclmodstart, exclmodend, modName) != exclmodend)
110 // Check for conflicts with used modules
111 // first the provided modules...
112 const_iterator provmodit = lay->providedModules().begin();
113 const_iterator const provmodend = lay->providedModules().end();
114 for (; provmodit != provmodend; ++provmodit) {
115 if (!LyXModule::areCompatible(modName, *provmodit))
118 // and then the selected modules
119 const_iterator mit = begin();
120 const_iterator const men = end();
121 for (; mit != men; ++mit)
122 if (!LyXModule::areCompatible(modName, *mit))
128 void LayoutModuleList::addDefaultModules(LayoutFile const * const lay,
129 std::list<string> removedModules)
131 LayoutModuleList mods = lay->defaultModules();
132 const_iterator mit = mods.begin();
133 const_iterator const men = mods.end();
135 // We want to insert the default modules at the beginning of
136 // the list, but also to insert them in the correct order.
137 // The obvious thing to do would be to collect them and then
138 // insert them, but that doesn't work because a later default
139 // module may require an earlier one, and then the test below
140 // moduleCanBeAdded(modname)
141 // will fail. So we have to do it a more complicated way.
142 iterator insertpos = begin();
145 for (; mit != men; ++mit) {
146 string const & modName = *mit;
147 // make sure the user hasn't removed it
148 if (find(removedModules.begin(), removedModules.end(), modName) !=
149 removedModules.end()) {
150 LYXERR(Debug::TCLASS, "Default module `" << modName <<
151 "' not added because removed by user.");
155 if (!moduleCanBeAdded(modName, lay)) {
156 // FIXME This could be because it's already present, so we should
157 // probably return something indicating that.
158 LYXERR(Debug::TCLASS, "Default module `" << modName <<
159 "' could not be added.");
162 LYXERR(Debug::TCLASS, "Default module `" << modName << "' added.");
163 insert(insertpos, modName);
164 // now we reset insertpos
167 advance(insertpos, numinserts);
172 bool LayoutModuleList::removeBadModules(LayoutFile const * const lay)
174 // we'll write a new list of modules, since we can't just remove them,
175 // as that would invalidate our iterators
176 LayoutModuleList oldModules = *this;
179 LayoutModuleList const & provmods = lay->providedModules();
180 LayoutModuleList const & exclmods = lay->excludedModules();
181 bool consistent = true; // set to false if we have to do anything
183 const_iterator oit = oldModules.begin();
184 const_iterator const oen = oldModules.end();
185 for (; oit != oen; ++oit) {
186 string const & modname = *oit;
187 // skip modules that the class provides
188 if (find(provmods.begin(), provmods.end(), modname) != provmods.end()) {
189 LYXERR0("Module `" << modname << "' dropped because provided by document class.");
193 // are we excluded by the document class?
194 if (find(exclmods.begin(), exclmods.end(), modname) != exclmods.end()) {
195 LYXERR0("Module `" << modname << "' dropped because excluded by document class.");
199 // determine whether some provided module excludes us or we exclude it
200 const_iterator pit = provmods.begin();
201 const_iterator const pen = provmods.end();
202 bool excluded = false;
203 for (; !excluded && pit != pen; ++pit) {
204 if (!LyXModule::areCompatible(modname, *pit)) {
205 LYXERR0("Module " << modname <<
206 " dropped because it conflicts with provided module `" << *pit << "'.");
219 // Perform a consistency check on the set of modules. We need to make
220 // sure that none of the modules exclude each other and that requires
222 bool LayoutModuleList::checkModuleConsistency(LayoutFile const * const lay)
224 bool consistent = true;
225 LayoutModuleList oldModules = *this;
227 const_iterator oit = oldModules.begin();
228 const_iterator const oen = oldModules.end();
229 LayoutModuleList const & provmods = lay->providedModules();
230 for (; oit != oen; ++oit) {
231 string const & modname = *oit;
232 bool excluded = false;
233 // Determine whether some prior module excludes us, or we exclude it
234 const_iterator lit = begin();
235 const_iterator const len = end();
236 for (; !excluded && lit != len; ++lit) {
237 if (!LyXModule::areCompatible(modname, *lit)) {
239 LYXERR0("Module " << modname <<
240 " dropped because it is excluded by prior module " << *lit);
248 // determine whether some provided module or some prior module
249 // satisfies our requirements
250 LyXModule const * const oldmod = theModuleList[modname];
252 LYXERR0("Default module " << modname <<
253 " added although it is unavailable and can't check requirements.");
257 vector<string> const & reqs = oldmod->getRequiredModules();
259 // we now set excluded to true, meaning that we haven't
260 // yet found a required module.
262 vector<string>::const_iterator rit = reqs.begin();
263 vector<string>::const_iterator const ren = reqs.end();
264 for (; rit != ren; ++rit) {
265 string const reqmod = *rit;
266 if (find(provmods.begin(), provmods.end(), reqmod) !=
271 if (find(begin(), end(), reqmod) != end()) {
279 LYXERR0("Module " << modname << " dropped because requirements not met.");
281 LYXERR(Debug::TCLASS, "Module " << modname << " passed consistency check.");