4 * This file is part of LyX, the document processor.
5 * Licence details can be found in the file COPYING.
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 // Is this module explicitly excluded by the document class?
71 const_iterator const exclmodstart = lay->excludedModules().begin();
72 const_iterator const exclmodend = lay->excludedModules().end();
73 if (find(exclmodstart, exclmodend, modName) != exclmodend)
76 // Is this module already provided by the document class?
77 const_iterator const provmodstart = lay->providedModules().begin();
78 const_iterator const provmodend = lay->providedModules().end();
79 if (find(provmodstart, provmodend, modName) != provmodend)
82 // Check for conflicts with used modules
83 // first the provided modules...
84 const_iterator provmodit = provmodstart;
85 for (; provmodit != provmodend; ++provmodit) {
86 if (!LyXModule::areCompatible(modName, *provmodit))
89 // and then the selected modules
90 const_iterator mit = begin();
91 const_iterator const men = end();
92 for (; mit != men; ++mit)
93 if (!LyXModule::areCompatible(modName, *mit))
96 // Check whether some required module is available
97 vector<string> const reqs = lm->getRequiredModules();
101 mit = begin(); // reset
102 vector<string>::const_iterator rit = reqs.begin();
103 vector<string>::const_iterator ren = reqs.end();
104 bool foundone = false;
105 for (; rit != ren; ++rit) {
106 if (find(mit, men, *rit) != men ||
107 find(provmodstart, provmodend, *rit) != provmodend) {
117 void LayoutModuleList::addDefaultModules(LayoutFile const * const lay,
118 std::list<string> removedModules)
120 LayoutModuleList mods = lay->defaultModules();
121 const_iterator mit = mods.begin();
122 const_iterator const men = mods.end();
124 // We want to insert the default modules at the beginning of
125 // the list, but also to insert them in the correct order.
126 // The obvious thing to do would be to collect them and then
127 // insert them, but that doesn't work because a later default
128 // module may require an earlier one, and then the test below
129 // moduleCanBeAdded(modname)
130 // will fail. So we have to do it a more complicated way.
131 iterator insertpos = begin();
134 for (; mit != men; mit++) {
135 string const & modName = *mit;
136 // make sure the user hasn't removed it
137 if (find(removedModules.begin(), removedModules.end(), modName) !=
138 removedModules.end()) {
139 LYXERR(Debug::TCLASS, "Default module `" << modName <<
140 "' not added because removed by user.");
144 if (!moduleCanBeAdded(modName, lay)) {
145 // FIXME This could be because it's already present, so we should
146 // probably return something indicating that.
147 LYXERR(Debug::TCLASS, "Default module `" << modName <<
148 "' could not be added.");
151 LYXERR(Debug::TCLASS, "Default module `" << modName << "' added.");
152 insert(insertpos, modName);
153 // now we reset insertpos
156 advance(insertpos, numinserts);
161 bool LayoutModuleList::removeBadModules(LayoutFile const * const lay)
163 // we'll write a new list of modules, since we can't just remove them,
164 // as that would invalidate our iterators
165 LayoutModuleList oldModules = *this;
168 LayoutModuleList const & provmods = lay->providedModules();
169 LayoutModuleList const & exclmods = lay->excludedModules();
170 bool consistent = true; // set to false if we have to do anything
172 const_iterator oit = oldModules.begin();
173 const_iterator const oen = oldModules.end();
174 for (; oit != oen; ++oit) {
175 string const & modname = *oit;
176 // skip modules that the class provides
177 if (find(provmods.begin(), provmods.end(), modname) != provmods.end()) {
178 LYXERR0("Module `" << modname << "' dropped because provided by document class.");
182 // are we excluded by the document class?
183 if (find(exclmods.begin(), exclmods.end(), modname) != exclmods.end()) {
184 LYXERR0("Module `" << modname << "' dropped because excluded by document class.");
188 // determine whether some provided module excludes us or we exclude it
189 const_iterator pit = provmods.begin();
190 const_iterator const pen = provmods.end();
191 bool excluded = false;
192 for (; !excluded && pit != pen; ++pit) {
193 if (!LyXModule::areCompatible(modname, *pit)) {
194 LYXERR0("Module " << modname <<
195 " dropped because it conflicts with provided module `" << *pit << "'.");
208 // Perform a consistency check on the set of modules. We need to make
209 // sure that none of the modules exclude each other and that requires
211 bool LayoutModuleList::checkModuleConsistency(LayoutFile const * const lay)
213 bool consistent = true;
214 LayoutModuleList oldModules = *this;
216 const_iterator oit = oldModules.begin();
217 const_iterator const oen = oldModules.end();
218 LayoutModuleList const & provmods = lay->providedModules();
219 for (; oit != oen; ++oit) {
220 string const & modname = *oit;
221 bool excluded = false;
222 // Determine whether some prior module excludes us, or we exclude it
223 const_iterator lit = begin();
224 const_iterator const len = end();
225 for (; !excluded && lit != len; ++lit) {
226 if (!LyXModule::areCompatible(modname, *lit)) {
228 LYXERR0("Module " << modname <<
229 " dropped because it is excluded by prior module " << *lit);
237 // determine whether some provided module or some prior module
238 // satisfies our requirements
239 LyXModule const * const oldmod = theModuleList[modname];
241 LYXERR0("Default module " << modname <<
242 " added although it is unavailable and can't check requirements.");
246 vector<string> const & reqs = oldmod->getRequiredModules();
248 // we now set excluded to true, meaning that we haven't
249 // yet found a required module.
251 vector<string>::const_iterator rit = reqs.begin();
252 vector<string>::const_iterator const ren = reqs.end();
253 for (; rit != ren; ++rit) {
254 string const reqmod = *rit;
255 if (find(provmods.begin(), provmods.end(), reqmod) !=
260 if (find(begin(), end(), reqmod) != end()) {
268 LYXERR0("Module " << modname << " dropped because requirements not met.");
270 LYXERR(Debug::TCLASS, "Module " << modname << " passed consistency check.");