rgheck wrote:

OK, here's this patch one more time, updated to current trunk. Comments welcome. I'll commit some time Tuesday unless there are objections.

By the way, does anyone know if the "by chapter" and "by section" modules should be included, excluded, or whatever from SIAM? I assume there is some fixed way they do things?

This time with the patch.

rh

Index: src/TextClass.h
===================================================================
--- src/TextClass.h	(revision 27002)
+++ src/TextClass.h	(working copy)
@@ -251,8 +251,12 @@
 	std::set<std::string> provides_;
 	/// latex packages requested by document class.
 	std::set<std::string> requires_;
-	/// modules wanted by document class
-	std::list<std::string> usemod_;
+	/// default modules wanted by document class
+	std::list<std::string> default_modules_;
+	/// modules provided by document class
+	std::list<std::string> provided_modules_;
+	/// modules excluded by document class
+	std::list<std::string> excluded_modules_;
 	///
 	unsigned int columns_;
 	///
Index: src/TextClass.cpp
===================================================================
--- src/TextClass.cpp	(revision 27002)
+++ src/TextClass.cpp	(working copy)
@@ -61,7 +61,7 @@
 };
 
 
-int const FORMAT = 10;
+int const FORMAT = 11;
 
 
 bool layout2layout(FileName const & filename, FileName const & tempfile)
@@ -183,7 +183,9 @@
 	TC_TITLELATEXTYPE,
 	TC_FORMAT,
 	TC_ADDTOPREAMBLE,
-	TC_USEMODULE
+	TC_DEFAULTMODULE,
+	TC_PROVIDESMODULE,
+	TC_EXCLUDESMODULE
 };
 
 
@@ -195,7 +197,9 @@
 		{ "columns",         TC_COLUMNS },
 		{ "counter",         TC_COUNTER },
 		{ "defaultfont",     TC_DEFAULTFONT },
+		{ "defaultmodule",   TC_DEFAULTMODULE },
 		{ "defaultstyle",    TC_DEFAULTSTYLE },
+		{ "excludesmodule",  TC_EXCLUDESMODULE },
 		{ "float",           TC_FLOAT },
 		{ "format",          TC_FORMAT },
 		{ "input",           TC_INPUT },
@@ -207,6 +211,7 @@
 		{ "pagestyle",       TC_PAGESTYLE },
 		{ "preamble",        TC_PREAMBLE },
 		{ "provides",        TC_PROVIDES },
+		{ "providesmodule",  TC_PROVIDESMODULE },
 		{ "requires",        TC_REQUIRES },
 		{ "rightmargin",     TC_RIGHTMARGIN },
 		{ "secnumdepth",     TC_SECNUMDEPTH },
@@ -214,8 +219,7 @@
 		{ "style",           TC_STYLE },
 		{ "titlelatexname",  TC_TITLELATEXNAME },
 		{ "titlelatextype",  TC_TITLELATEXTYPE },
-		{ "tocdepth",        TC_TOCDEPTH },
-		{ "usemodule",       TC_USEMODULE }
+		{ "tocdepth",        TC_TOCDEPTH }
 	};
 	
 } //namespace anon
@@ -489,14 +493,35 @@
 			break;
 		}
 
-		case TC_USEMODULE: {
+		case TC_DEFAULTMODULE: {
 			lexrc.next();
 			string const module = lexrc.getString();
-			if (find(usemod_.begin(), usemod_.end(), module) == usemod_.end())
-				usemod_.push_back(module);
+			if (find(default_modules_.begin(), default_modules_.end(), module) == default_modules_.end())
+				default_modules_.push_back(module);
 			break;
 		}
 
+		case TC_PROVIDESMODULE: {
+			lexrc.next();
+			string const module = lexrc.getString();
+			if (find(provided_modules_.begin(), provided_modules_.end(), module) == provided_modules_.end())
+				provided_modules_.push_back(module);
+			break;
+		}
+
+		case TC_EXCLUDESMODULE: {
+			lexrc.next();
+			string const module = lexrc.getString();
+			// modules already have their own way to exclude other modules
+			if (rt == MODULE) {
+				LYXERR0("ExcludesModule tag cannot be used in a module!");
+				break;
+			}
+			if (find(excluded_modules_.begin(), excluded_modules_.end(), module) == excluded_modules_.end())
+				excluded_modules_.push_back(module);
+			break;
+		}
+
 		case TC_LEFTMARGIN:	// left margin type
 			if (lexrc.next())
 				leftmargin_ = lexrc.getDocString();
Index: src/LayoutFile.h
===================================================================
--- src/LayoutFile.h	(revision 27002)
+++ src/LayoutFile.h	(working copy)
@@ -65,7 +65,11 @@
 	bool isTeXClassAvailable() const { return texClassAvail_; }
 	///
 	std::list<std::string> const & defaultModules() const 
-			{ return usemod_; }
+			{ return default_modules_; }
+ 	std::list<std::string> const & providedModules() const 
+ 			{ return provided_modules_; }
+ 	std::list<std::string> const & excludedModules() const 
+ 			{ return excluded_modules_; }
 private:
 	/// Construct a layout with default values. Actual values loaded later.
 	explicit LayoutFile(std::string const & filename,
Index: src/BufferParams.h
===================================================================
--- src/BufferParams.h	(revision 27002)
+++ src/BufferParams.h	(working copy)
@@ -347,6 +347,12 @@
 	void readRemovedModules(Lexer &);
 	///
 	void addDefaultModules();
+	/// checks for consistency among modules: makes sure requirements
+	/// are met, no modules exclude one another, etc, and resolves any
+	/// such conflicts, leaving us with a consistent collection.
+	/// \return true if modules were consistent, false if changes had
+	/// to be made.
+	bool checkModuleConsistency();
 
 	/// for use with natbib
 	CiteEngine cite_engine_;
Index: src/BufferParams.cpp
===================================================================
--- src/BufferParams.cpp	(revision 27002)
+++ src/BufferParams.cpp	(working copy)
@@ -1503,6 +1503,105 @@
 }
 
 
+bool BufferParams::checkModuleConsistency() {
+	bool consistent = true;
+	// Perform a consistency check on the set of modules.
+	// In particular, we need to check that modules provided by this class
+	// do not conflict with modules chosen by the user.
+	list<string> oldModules = getModules();
+	clearLayoutModules();
+	list<string>::const_iterator oit = oldModules.begin();
+	list<string>::const_iterator oen = oldModules.end();
+	list<string> const & provmods = baseClass()->providedModules();
+	list<string> const & exclmods = baseClass()->excludedModules();
+	for (; oit != oen; ++oit) {
+		string const & modname = *oit;
+		// skip modules that the class provides
+		if (find(provmods.begin(), provmods.end(), modname) != provmods.end()) {
+			consistent = false;
+			LYXERR0("Module " << modname << " dropped because provided by document class.");
+			continue;
+		}
+		// are we excluded by the document class?
+		if (find(exclmods.begin(), exclmods.end(), modname) != exclmods.end()) {
+			consistent = false;
+			LYXERR0("Module " << modname << " dropped because excluded by document class.");
+			continue;
+		}
+
+		// determine whether some provided module excludes us or we exclude it
+		list<string>::const_iterator pit = provmods.begin();
+		list<string>::const_iterator pen = provmods.end();
+		bool excluded = false;
+		for (; !excluded && pit != pen; ++pit) {
+			if (!LyXModule::areCompatible(modname, *pit)) {
+				consistent = false;
+				LYXERR0("Module " << modname << 
+						" dropped becuase it conflicts with provided module " << *pit);
+				excluded = true;
+			}
+		}
+
+		if (excluded)
+			continue;
+
+		// Determine whether some prior module excludes us, or we exclude it
+		list<string>::const_iterator lit = layoutModules_.begin();
+		list<string>::const_iterator len = layoutModules_.end();
+		for (; !excluded && lit != len; ++lit) {
+			if (!LyXModule::areCompatible(modname, *lit)) {
+				consistent = false;
+				LYXERR0("Module " << modname << 
+						" dropped because it is excluded by prior module " << *lit);
+				excluded = true;
+			}
+		}
+
+		if (excluded)
+			continue;
+
+		// determine whether some provided module or some prior module
+		// satisfies our requirements
+		LyXModule const * const oldmod = moduleList[modname];
+		if (!oldmod) {
+			LYXERR0("Default module " << modname << 
+					" added although it is unavailable and can't check requirements.");
+			continue;
+		}
+			
+		vector<string> const & reqs = oldmod->getRequiredModules();
+		if (!reqs.empty()) {
+			// we now set excluded to true, meaning that we haven't
+			// yet found a required module.
+			excluded = true;
+			vector<string>::const_iterator rit  = reqs.begin();
+			vector<string>::const_iterator ren = reqs.end();
+			for (; rit != ren; ++rit) {
+				string const reqmod = *rit;
+				if (find(provmods.begin(), provmods.end(), reqmod) != 
+						provmods.end()) {
+					excluded = false;
+					break;
+				}
+				if (find(layoutModules_.begin(), layoutModules_.end(), reqmod) != 
+						layoutModules_.end()) {
+					excluded = false;
+					break;
+				}
+			}
+		}
+		if (excluded) {
+			consistent = false;
+			LYXERR0("Module " << modname << " dropped because requirements not met.");
+		} else {
+			LYXERR(Debug::TCLASS, "Module " << modname << " passed consistency check.");
+			layoutModules_.push_back(modname);
+		}
+	}
+	return consistent;
+}
+
+
 bool BufferParams::setBaseClass(string const & classname)
 {
 	LYXERR(Debug::TCLASS, "setBaseClass: " << classname);
@@ -1529,6 +1628,7 @@
 
 	pimpl_->baseClass_ = classname;
 	addDefaultModules();
+	checkModuleConsistency();
 
 	return true;
 }
@@ -1611,9 +1711,32 @@
 	if (!lm)
 		return true;
 
+	// Is this module explicitly excluded by the document class?
+	list<string>::const_iterator const exclmodstart = 
+			baseClass()->excludedModules().begin();
+	list<string>::const_iterator const exclmodend = 
+			baseClass()->excludedModules().end();
+	if (find(exclmodstart, exclmodend, modName) != exclmodend)
+		return false;
+
+	// Is this module already provided by the document class?
+	list<string>::const_iterator const provmodstart = 
+			baseClass()->providedModules().begin();
+	list<string>::const_iterator const provmodend = 
+			baseClass()->providedModules().end();
+	if (find(provmodstart, provmodend, modName) != provmodend)
+		return false;
+
+	// Check for conflicts with used modules
+	// first the provided modules...
+	list<string>::const_iterator provmodit = provmodstart;
+	for (; provmodit != provmodend; ++provmodit) {
+		if (!LyXModule::areCompatible(modName, *provmodit))
+			return false;
+	}
+	// and then the selected modules
 	LayoutModuleList::const_iterator mit = getModules().begin();
 	LayoutModuleList::const_iterator const men = getModules().end();
-	// Check for conflicts with used modules
 	for (; mit != men; ++mit)
 		if (!LyXModule::areCompatible(modName, *mit))
 			return false;
@@ -1628,7 +1751,8 @@
 	vector<string>::const_iterator ren = reqs.end();
 	bool foundone = false;
 	for (; rit != ren; ++rit) {
-		if (find(mit, men, *rit) != men) {
+		if (find(mit, men, *rit) != men || 
+		    find(provmodstart, provmodend, *rit) != provmodend) {
 			foundone = true;
 			break;
 		}
Index: src/frontends/qt4/GuiDocument.h
===================================================================
--- src/frontends/qt4/GuiDocument.h	(revision 27002)
+++ src/frontends/qt4/GuiDocument.h	(working copy)
@@ -184,7 +184,12 @@
 	std::list<modInfoStruct> const & getModuleInfo();
 	/// Modules in use in current buffer
 	std::list<modInfoStruct> const getSelectedModules();
+ 	///
+	std::list<modInfoStruct> const getProvidedModules();
 	///
+	std::list<modInfoStruct> const 
+			makeModuleInfo(std::list<std::string> const & mods);
+	///
 	void setLanguage() const;
 	///
 	void saveAsDefault() const;
Index: src/frontends/qt4/GuiDocument.cpp
===================================================================
--- src/frontends/qt4/GuiDocument.cpp	(revision 27002)
+++ src/frontends/qt4/GuiDocument.cpp	(working copy)
@@ -249,6 +249,12 @@
 	: GuiSelectionManager(availableLV, selectedLV, addPB, delPB,
 				upPB, downPB, availableModel, selectedModel), container_(container)
 		{}
+	///
+	void updateProvidedModules(std::list<std::string> const & pm) 
+			{ provided_modules_ = pm; }
+	///
+	void updateExcludedModules(std::list<std::string> const & em) 
+			{ excluded_modules_ = em; }
 private:
 	///
 	virtual void updateAddPB();
@@ -268,6 +274,10 @@
 	{
 		return dynamic_cast<GuiIdListModel *>(selectedModel);
 	}
+	/// keeps a list of the modules the text class provides
+	std::list<std::string> provided_modules_;
+	/// similarly...
+	std::list<std::string> excluded_modules_;
 	/// 
 	GuiDocument const * container_;
 };
@@ -1339,8 +1349,6 @@
 	// class. So when we set the base class, we also need to recreate the document 
 	// class. Otherwise, we still have the old one.
 	bp_.makeDocumentClass();
-	// the new class may require some default modules.
-	updateSelectedModules();
 	paramsToDialog();
 }
 
@@ -1447,6 +1455,13 @@
 	string const modName = id_model.getIDString(idx.row());
 	docstring desc = getModuleDescription(modName);
 
+	list<string> const & provmods = bp_.baseClass()->providedModules();
+	if (std::find(provmods.begin(), provmods.end(), modName) != provmods.end()) {
+		if (!desc.empty())
+			desc += "\n";
+		desc += _("Module provided by document class.");
+	}
+
 	vector<string> pkglist = getPackageList(modName);
 	docstring pkgdesc = formatStrVec(pkglist, _("and"));
 	if (!pkgdesc.empty()) {
@@ -2003,6 +2018,11 @@
 	// latex
 	latexModule->defaultOptionsCB->setChecked(
 			bp_.use_default_options);
+	updateSelectedModules();
+	selectionManager->updateProvidedModules(
+			bp_.baseClass()->providedModules());
+	selectionManager->updateExcludedModules(
+			bp_.baseClass()->excludedModules());
 
 	if (!documentClass().options().empty()) {
 		latexModule->defaultOptionsLE->setText(
@@ -2249,7 +2269,6 @@
 	bp_ = view->buffer().params();
 	loadModuleInfo();
 	updateAvailableModules();
-	updateSelectedModules();
 	//FIXME It'd be nice to make sure here that the selected
 	//modules are consistent: That required modules are actually
 	//selected, and that we don't have conflicts. If so, we could
@@ -2278,9 +2297,9 @@
 }
 
 
-list<GuiDocument::modInfoStruct> const GuiDocument::getSelectedModules()
+list<GuiDocument::modInfoStruct> const 
+		GuiDocument::makeModuleInfo(list<string> const & mods)
 {
-	list<string> const & mods = params().getModules();
 	list<string>::const_iterator it =  mods.begin();
 	list<string>::const_iterator end = mods.end();
 	list<modInfoStruct> mInfo;
@@ -2298,6 +2317,18 @@
 }
 
 
+list<GuiDocument::modInfoStruct> const GuiDocument::getSelectedModules()
+{
+	return makeModuleInfo(params().getModules());
+}
+
+
+list<GuiDocument::modInfoStruct> const GuiDocument::getProvidedModules()
+{
+	return makeModuleInfo(params().baseClass()->providedModules());
+}
+
+
 DocumentClass const & GuiDocument::documentClass() const
 {
 	return bp_.documentClass();
Index: src/ModuleList.h
===================================================================
--- src/ModuleList.h	(revision 27002)
+++ src/ModuleList.h	(working copy)
@@ -40,6 +40,9 @@
  *  The description is used in the gui to give information to the user. The
  *  Requires and Excludes lines are read by the configuration script and
  *  written to a file lyxmodules.lst in the user configuration directory.
+ *
+ *  Modules can also be "provided" or "excluded" by document classes, using
+ *  the ProvidesModule and ExcludesModule tags.
  */
 
 class LyXModule {
Index: lib/scripts/layout2layout.py
===================================================================
--- lib/scripts/layout2layout.py	(revision 27002)
+++ lib/scripts/layout2layout.py	(working copy)
@@ -36,9 +36,12 @@
 # Incremented to format 10, 6 October 2008 by rgh
 # Change format of counters
 
-currentFormat = 10
+# Incremented to format 11, 14 October 2008 by rgh
+# Add ProvidesModule, ExcludesModule tags
 
+currentFormat = 11
 
+
 def usage(prog_name):
     return ("Usage: %s inputfile outputfile\n" % prog_name +
             "or     %s <inputfile >outputfile" % prog_name)
@@ -98,6 +101,7 @@
     re_Comment = re.compile(r'^(\s*)#')
     re_Counter = re.compile(r'\s*Counter\s*', re.IGNORECASE)
     re_Name = re.compile(r'\s*Name\s+(\S+)\s*', re.IGNORECASE)
+    re_UseMod = re.compile(r'^\s*UseModule\s+(.*)', re.IGNORECASE)
     re_Empty = re.compile(r'^(\s*)$')
     re_Format = re.compile(r'^(\s*)(Format)(\s+)(\S+)', re.IGNORECASE)
     re_Preamble = re.compile(r'^(\s*)Preamble', re.IGNORECASE)
@@ -193,6 +197,14 @@
                 i += 1
             continue
 
+        if format == 10:
+            match = re_UseMod.match(lines[i])
+            if match:
+                module = match.group(1)
+                lines[i] = "DefaultModule " + module
+            i += 1
+            continue
+
         if format == 9:
             match = re_Counter.match(lines[i])
             if match:
Index: lib/layouts/siamltex.layout
===================================================================
--- lib/layouts/siamltex.layout	(revision 27002)
+++ lib/layouts/siamltex.layout	(working copy)
@@ -10,7 +10,7 @@
 # Modified from  amsart.layout May '08 by Andrew Corrigan <[EMAIL PROTECTED]>
 
 
-Format 10
+Format 11
 Columns                 1
 Sides                   2
 PageStyle               Headers
@@ -21,10 +21,11 @@
 	FontSize   8|9|10|11|12
 End
 
-# FIXME: this is not ideal, but we cannot
-# load the module regularly, because we 
-# have to disable some layouts (see below)
+# We need to load the module this way 
+# so we can disable some layouts below.
 Input theorems-ams.module
+ProvidesModule theorems-ams
+ExcludesModule theorems-ams-extended
 
 Style Standard
 	Category              MainText
Index: lib/doc/Customization.lyx
===================================================================
--- lib/doc/Customization.lyx	(revision 27002)
+++ lib/doc/Customization.lyx	(working copy)
@@ -5994,6 +5994,12 @@
 \end_layout
 
 \begin_layout Subsection
+\begin_inset CommandInset label
+LatexCommand label
+name "sub:Layout-modules"
+
+\end_inset
+
 Layout modules
 \end_layout
 
@@ -7123,6 +7129,43 @@
 status collapsed
 
 \begin_layout Plain Layout
+DefaultModule
+\end_layout
+
+\end_inset
+
+ [
+\begin_inset Flex CharStyle:Code
+status collapsed
+
+\begin_layout Plain Layout
+string]
+\end_layout
+
+\end_inset
+
+ Specifies a module to be included by default with this document class,
+ which should be specified by filename without the 
+\begin_inset Flex CharStyle:Code
+status collapsed
+
+\begin_layout Plain Layout
+.module
+\end_layout
+
+\end_inset
+
+ extension.
+ The user can still remove the module, but it will be active at the outset.
+ (This applies only when new files are created, or when this class is chosen
+ for an existing document.)
+\end_layout
+
+\begin_layout Description
+\begin_inset Flex CharStyle:Code
+status collapsed
+
+\begin_layout Plain Layout
 DefaultStyle
 \end_layout
 
@@ -7158,6 +7201,65 @@
 status collapsed
 
 \begin_layout Plain Layout
+ExcludesModule
+\end_layout
+
+\end_inset
+
+ [
+\begin_inset Flex CharStyle:Code
+status collapsed
+
+\begin_layout Plain Layout
+string
+\end_layout
+
+\end_inset
+
+] Indicates that the module in question---which should be specified by filename
+ without the 
+\begin_inset Flex CharStyle:Code
+status collapsed
+
+\begin_layout Plain Layout
+.module
+\end_layout
+
+\end_inset
+
+ extension---cannot be used with this document class.
+ This might be used in a journal-specific layout file to prevent, say, the
+ use of the 
+\begin_inset Flex CharStyle:Code
+status collapsed
+
+\begin_layout Plain Layout
+theorems-sec
+\end_layout
+
+\end_inset
+
+ module that numbers theorems by section.
+ This tag may 
+\emph on
+not
+\emph default
+ be used in a module.
+ Modules have their own way of excluding other modules (see 
+\begin_inset CommandInset ref
+LatexCommand ref
+reference "sub:Layout-modules"
+
+\end_inset
+
+).
+\end_layout
+
+\begin_layout Description
+\begin_inset Flex CharStyle:Code
+status collapsed
+
+\begin_layout Plain Layout
 Float
 \end_layout
 
@@ -7593,6 +7695,55 @@
 status collapsed
 
 \begin_layout Plain Layout
+ProvidesModule
+\end_layout
+
+\end_inset
+
+ [
+\begin_inset Flex CharStyle:Code
+status collapsed
+
+\begin_layout Plain Layout
+string
+\end_layout
+
+\end_inset
+
+] Indicates that this layout provides the functionality of the module mentioned,
+ which should be specified by filename, which should be specified by filename
+ without the 
+\begin_inset Flex CharStyle:Code
+status collapsed
+
+\begin_layout Plain Layout
+.module
+\end_layout
+
+\end_inset
+
+ extension.
+ This will typically be used if the layout includes the module directly,
+ rather than using the 
+\begin_inset Flex CharStyle:Code
+status collapsed
+
+\begin_layout Plain Layout
+DefaultModule
+\end_layout
+
+\end_inset
+
+ tag to indicate that it ought to be used.
+ It could be used in a module that that provided an alternate implementation
+ of the same functionality.
+\end_layout
+
+\begin_layout Description
+\begin_inset Flex CharStyle:Code
+status collapsed
+
+\begin_layout Plain Layout
 Requires
 \end_layout
 
@@ -7944,32 +8095,6 @@
  counter in LaTeX.
 \end_layout
 
-\begin_layout Description
-\begin_inset Flex CharStyle:Code
-status collapsed
-
-\begin_layout Plain Layout
-UseModule
-\end_layout
-
-\end_inset
-
- [
-\begin_inset Flex CharStyle:Code
-status collapsed
-
-\begin_layout Plain Layout
-string]
-\end_layout
-
-\end_inset
-
- Specifies a module to be included by default with this document class.
- The user can still remove the module, but it will be active at the outset.
- (This applies only when new files are created, or when this class is chosen
- for an existing document.)
-\end_layout
-
 \begin_layout Subsection
 \begin_inset Flex CharStyle:Code
 status collapsed

Reply via email to