This patch introduces ProvidesModule and ExcludesModule layout tags.

See http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg145129.html.


git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@27041 a592a061-630c-0410-9148-cb99ea01b6c8
This commit is contained in:
Richard Heck 2008-10-23 00:27:03 +00:00
parent 66f9f10c83
commit 9dfac74265
11 changed files with 388 additions and 48 deletions

View File

@ -5994,6 +5994,12 @@ default
\end_layout
\begin_layout Subsection
\begin_inset CommandInset label
LatexCommand label
name "sub:Layout-modules"
\end_inset
Layout modules
\end_layout
@ -7122,6 +7128,43 @@ EndFont
\begin_inset Flex CharStyle:Code
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
@ -7157,6 +7200,65 @@ Standard
\begin_inset Flex CharStyle:Code
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
@ -7592,6 +7694,55 @@ aTeX Configuration
\begin_inset Flex CharStyle:Code
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 @@ tocdepth
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

View File

@ -10,7 +10,7 @@
# Modified from amsart.layout May '08 by Andrew Corrigan <acorriga@gmu.edu>
Format 10
Format 11
Columns 1
Sides 2
PageStyle Headers
@ -21,10 +21,11 @@ ClassOptions
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

View File

@ -36,7 +36,10 @@ import os, re, string, sys
# 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):
@ -98,6 +101,7 @@ def convert(lines):
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 @@ def convert(lines):
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:

View File

@ -1503,6 +1503,105 @@ void BufferParams::addDefaultModules()
}
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 @@ bool BufferParams::setBaseClass(string const & classname)
pimpl_->baseClass_ = classname;
addDefaultModules();
checkModuleConsistency();
return true;
}
@ -1611,9 +1711,32 @@ bool BufferParams::moduleCanBeAdded(string const & modName) const
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 @@ bool BufferParams::moduleCanBeAdded(string const & modName) const
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;
}

View File

@ -347,6 +347,12 @@ private:
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_;

View File

@ -65,7 +65,11 @@ public:
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,

View File

@ -40,6 +40,9 @@ namespace lyx {
* 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 {

View File

@ -61,7 +61,7 @@ private:
};
int const FORMAT = 10;
int const FORMAT = 11;
bool layout2layout(FileName const & filename, FileName const & tempfile)
@ -183,7 +183,9 @@ enum TextClassTags {
TC_TITLELATEXTYPE,
TC_FORMAT,
TC_ADDTOPREAMBLE,
TC_USEMODULE
TC_DEFAULTMODULE,
TC_PROVIDESMODULE,
TC_EXCLUDESMODULE
};
@ -195,7 +197,9 @@ namespace {
{ "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 @@ namespace {
{ "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 @@ namespace {
{ "style", TC_STYLE },
{ "titlelatexname", TC_TITLELATEXNAME },
{ "titlelatextype", TC_TITLELATEXTYPE },
{ "tocdepth", TC_TOCDEPTH },
{ "usemodule", TC_USEMODULE }
{ "tocdepth", TC_TOCDEPTH }
};
} //namespace anon
@ -489,11 +493,32 @@ TextClass::ReturnValues TextClass::read(Lexer & lexrc, ReadType rt)
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;
}

View File

@ -251,8 +251,12 @@ protected:
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_;
///

View File

@ -249,6 +249,12 @@ public:
: 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 @@ private:
{
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 @@ void GuiDocument::classChanged()
// 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 @@ void GuiDocument::updateModuleInfo()
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 @@ void GuiDocument::paramsToDialog()
// 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 @@ bool GuiDocument::initialiseParams(string const &)
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::getModuleInfo()
}
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()
}
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();

View File

@ -184,6 +184,11 @@ private:
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;
///