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"
29 // the previous document class may have loaded some modules that the
30 // new one excludes, and the new class may provide, etc, some that
31 // conflict with ones that were already loaded. So we need to go
32 // through the list and fix everything. I suppose there are various
33 // ways this could be done, but the following seems to work at the
34 // moment. (Thanks to Philippe Charpentier for helping work out all
36 bool LayoutModuleList::adaptToBaseClass(LayoutFile const * const lay,
37 std::list<string> removedModules)
39 // first, we remove any modules the new document class itself provides,
40 // those it excludes, and those that conflict with ones it excludes.
41 // this has to be done first because, otherwise, a module we're about
42 // to remove could prevent a default module from being added.
43 bool retval = removeBadModules(lay);
44 // next, we add any default modules the new class provides.
45 addDefaultModules(lay, removedModules);
46 // finally, we perform a general consistency check on the set of
47 // loaded modules. it's a hassle that we have to do this now, since
48 // we just went through them a bit ago, but things might have changed
49 // with the loading of the default modules.
50 retval |= checkModuleConsistency(lay);
55 bool LayoutModuleList::moduleCanBeAdded(string const & modName,
56 LayoutFile const * const lay) const
58 // Is the module already present?
59 const_iterator it = begin();
60 const_iterator const en = end();
61 for (; it != en; it++)
65 LyXModule const * const lm = moduleList[modName];
69 // Is this module explicitly excluded by the document class?
70 const_iterator const exclmodstart = lay->excludedModules().begin();
71 const_iterator const exclmodend = lay->excludedModules().end();
72 if (find(exclmodstart, exclmodend, modName) != exclmodend)
75 // Is this module already provided by the document class?
76 const_iterator const provmodstart = lay->providedModules().begin();
77 const_iterator const provmodend = lay->providedModules().end();
78 if (find(provmodstart, provmodend, modName) != provmodend)
81 // Check for conflicts with used modules
82 // first the provided modules...
83 const_iterator provmodit = provmodstart;
84 for (; provmodit != provmodend; ++provmodit) {
85 if (!LyXModule::areCompatible(modName, *provmodit))
88 // and then the selected modules
89 const_iterator mit = begin();
90 const_iterator const men = end();
91 for (; mit != men; ++mit)
92 if (!LyXModule::areCompatible(modName, *mit))
95 // Check whether some required module is available
96 vector<string> const reqs = lm->getRequiredModules();
100 mit = begin(); // reset
101 vector<string>::const_iterator rit = reqs.begin();
102 vector<string>::const_iterator ren = reqs.end();
103 bool foundone = false;
104 for (; rit != ren; ++rit) {
105 if (find(mit, men, *rit) != men ||
106 find(provmodstart, provmodend, *rit) != provmodend) {
116 void LayoutModuleList::addDefaultModules(LayoutFile const * const lay,
117 std::list<string> removedModules)
119 LayoutModuleList mods = lay->defaultModules();
120 const_iterator mit = mods.begin();
121 const_iterator const men = mods.end();
123 // We want to insert the default modules at the beginning of
124 // the list, but also to insert them in the correct order.
125 // The obvious thing to do would be to collect them and then
126 // insert them, but that doesn't work because a later default
127 // module may require an earlier one, and then the test below
128 // moduleCanBeAdded(modname)
129 // will fail. So we have to do it a more complicated way.
130 iterator insertpos = begin();
133 for (; mit != men; mit++) {
134 string const & modName = *mit;
135 // make sure the user hasn't removed it
136 if (find(removedModules.begin(), removedModules.end(), modName) !=
137 removedModules.end()) {
138 LYXERR(Debug::TCLASS, "Default module `" << modName <<
139 "' not added because removed by user.");
143 if (!moduleCanBeAdded(modName, lay)) {
144 // FIXME This could be because it's already present, so we should
145 // probably return something indicating that.
146 LYXERR(Debug::TCLASS, "Default module `" << modName <<
147 "' could not be added.");
150 LYXERR(Debug::TCLASS, "Default module `" << modName << "' added.");
151 insert(insertpos, modName);
152 // now we reset insertpos
155 advance(insertpos, numinserts);
160 bool LayoutModuleList::removeBadModules(LayoutFile const * const lay)
162 // we'll write a new list of modules, since we can't just remove them,
163 // as that would invalidate our iterators
164 LayoutModuleList oldModules = *this;
167 LayoutModuleList const & provmods = lay->providedModules();
168 LayoutModuleList const & exclmods = lay->excludedModules();
169 bool consistent = true; // set to false if we have to do anything
171 const_iterator oit = oldModules.begin();
172 const_iterator const oen = oldModules.end();
173 for (; oit != oen; ++oit) {
174 string const & modname = *oit;
175 // skip modules that the class provides
176 if (find(provmods.begin(), provmods.end(), modname) != provmods.end()) {
177 LYXERR0("Module `" << modname << "' dropped because provided by document class.");
181 // are we excluded by the document class?
182 if (find(exclmods.begin(), exclmods.end(), modname) != exclmods.end()) {
183 LYXERR0("Module `" << modname << "' dropped because excluded by document class.");
187 // determine whether some provided module excludes us or we exclude it
188 const_iterator pit = provmods.begin();
189 const_iterator const pen = provmods.end();
190 bool excluded = false;
191 for (; !excluded && pit != pen; ++pit) {
192 if (!LyXModule::areCompatible(modname, *pit)) {
193 LYXERR0("Module " << modname <<
194 " dropped becuase it conflicts with provided module `" << *pit << "'.");
207 // Perform a consistency check on the set of modules. We need to make
208 // sure that none of the modules exclude each other and that requires
210 bool LayoutModuleList::checkModuleConsistency(LayoutFile const * const lay) {
211 bool consistent = true;
212 LayoutModuleList oldModules = *this;
214 const_iterator oit = oldModules.begin();
215 const_iterator const oen = oldModules.end();
216 LayoutModuleList const & provmods = lay->providedModules();
217 for (; oit != oen; ++oit) {
218 string const & modname = *oit;
219 bool excluded = false;
220 // Determine whether some prior module excludes us, or we exclude it
221 const_iterator lit = begin();
222 const_iterator const len = end();
223 for (; !excluded && lit != len; ++lit) {
224 if (!LyXModule::areCompatible(modname, *lit)) {
226 LYXERR0("Module " << modname <<
227 " dropped because it is excluded by prior module " << *lit);
235 // determine whether some provided module or some prior module
236 // satisfies our requirements
237 LyXModule const * const oldmod = moduleList[modname];
239 LYXERR0("Default module " << modname <<
240 " added although it is unavailable and can't check requirements.");
244 vector<string> const & reqs = oldmod->getRequiredModules();
246 // we now set excluded to true, meaning that we haven't
247 // yet found a required module.
249 vector<string>::const_iterator rit = reqs.begin();
250 vector<string>::const_iterator const ren = reqs.end();
251 for (; rit != ren; ++rit) {
252 string const reqmod = *rit;
253 if (find(provmods.begin(), provmods.end(), reqmod) !=
258 if (find(begin(), end(), reqmod) != end()) {
266 LYXERR0("Module " << modname << " dropped because requirements not met.");
268 LYXERR(Debug::TCLASS, "Module " << modname << " passed consistency check.");