]> git.lyx.org Git - features.git/commitdiff
This patch introduces ProvidesModule and ExcludesModule layout tags.
authorRichard Heck <rgheck@comcast.net>
Thu, 23 Oct 2008 00:27:03 +0000 (00:27 +0000)
committerRichard Heck <rgheck@comcast.net>
Thu, 23 Oct 2008 00:27:03 +0000 (00:27 +0000)
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

lib/doc/Customization.lyx
lib/layouts/siamltex.layout
lib/scripts/layout2layout.py
src/BufferParams.cpp
src/BufferParams.h
src/LayoutFile.h
src/ModuleList.h
src/TextClass.cpp
src/TextClass.h
src/frontends/qt4/GuiDocument.cpp
src/frontends/qt4/GuiDocument.h

index cabc866db11216fe92067716089774bbabb760b6..3ffff17935a43fac50d703a8ad2a26504a8d6742 100644 (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
index b8b8a30ab76e1883f34d2e1dbbb7edfab6c65ba1..233416833bda628a130070e7f84a3808196d9428 100644 (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
index 583771a86a9b8386668f4b47d714b33353c12711..af5ab1d44f508d7f39454cfe28f3e2d4a4b5f569 100644 (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:
index b545bf88f3b79d86a70f0255bec0fa6548a2fbd8..3a8b25b5e723ed763b57adf820fb7aaaf929dd37 100644 (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;
                }
index 8e45cc7fe5915222606117f32e18e31fd22fcd1f..af7333364b3b1aee59131990541d925acf0bc8b4 100644 (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_;
index 60f6f6399617fc6227dc8a5116dde4e9167db898..bf6e52b8254d9343ce0f6048847994c28627eb8c 100644 (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,
index fef293bbcc6b3c220c30d4f1985752732f053d07..66353affe35928ad443503fe3f5aac64733eda1c 100644 (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 {
index c6e759dcf025d7a254273ff86f282bc47c295806..8ccda464b928a3ed2ebb4b1d1d011530632d2d21 100644 (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;
                }
 
index b9d88dbf2298f34eeea5bc5986bf23a71c135b0a..456765eac150476c1ae174b55527e24a8d7edfe7 100644 (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_;
        ///
index c252dc6cbc199d73917f04db0a9ea8525fc708ea..f185ccb18384dc34bc288fb34589197279527a0e 100644 (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();
index 5b2066f7c0a2a8b7a016f32539926257a027a1cf..c5c1c55bf1da09bfa956dc441a449ed8b235a253 100644 (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;
        ///