This commit adds some new functionality to the modules stuff. In particular, it introduces the concept of "required" and "excluded" modules: A given module may require one of some list of modules, or it may be incompatible with some other modules. (Complex Boolean combinations are not supported!!) These facts can be noted in the module file, and the UI responds appropriately: Required and excluded modules are noted in the description, and the "Add" button is enabled only if at least one of the required modules has already been selected and no excluded module is selected. Getting this to work involved a fair bit of cleanup of the existing code---including ways Angus, I think, had already pointed out were required---and also involved changing the syntax of the headers of the module files, but in ways that are probably best anyway.

None of the extant modules require any other modules, but the Theorem modules all exclude one another. (See the screenshot.) When I modularize the AMS classes---that is the next task---we'll have requires.


git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@22456 a592a061-630c-0410-9148-cb99ea01b6c8
This commit is contained in:
Richard Heck 2008-01-09 18:51:02 +00:00
parent e975835530
commit 7c28905b17
20 changed files with 504 additions and 129 deletions

View File

@ -730,35 +730,73 @@ def checkModulesConfig():
tx.close()
print '\tdone'
def processModuleFile(file, bool_docbook, bool_linuxdoc):
''' process module file and get a line of result
Declare lines look like this:
\DeclareLyXModule[LaTeX Packages]{Description}{ModuleName}...
The top of a module file should look like this:
#\DeclareLyXModule[LaTeX Packages]{ModuleName}
#BeginDescription
#...body of description...
#EndDescription
#Requires: [list of required modules]
#Excludes: [list of excluded modules]
The last two lines are optional
We expect output:
"ModuleName" "filename" "Description" "Packages"
"
"ModuleName" "filename" "Description" "Packages" "Requires" "Excludes"
'''
p = re.compile(r'\DeclareLyXModule\s*(?:\[([^]]*)\])?{(.*)}{(.*)}')
for line in open(file).readlines():
res = p.search(line)
if res != None:
(packages, desc, modname) = res.groups()
#check availability...need to add that
if packages == None:
packages = ""
else:
pkgs = [s.strip() for s in packages.split(",")]
packages = ",".join(pkgs)
p = re.compile(r'\DeclareLyXModule\s*(?:\[([^]]*?)\])?{(.*)}')
r = re.compile(r'#+\s*Requires: (.*)')
x = re.compile(r'#+\s*Excludes: (.*)')
b = re.compile(r'#+\s*DescriptionBegin\s*$')
e = re.compile(r'#+\s*DescriptionEnd\s*$')
filename = file.split(os.sep)[-1]
return '"%s" "%s" "%s" "%s"\n' % (modname, filename, desc, packages)
modname = desc = pkgs = req = excl = ""
readingDescription = False
descLines = []
for line in open(file).readlines():
if readingDescription:
res = e.search(line)
if res != None:
readingDescription = False
desc = " ".join(descLines)
continue
descLines.append(line[1:].strip())
continue
res = b.search(line)
if res != None:
readingDescription = True
continue
res = p.search(line)
if res != None:
(pkgs, modname) = res.groups()
if pkgs == None:
pkgs = ""
else:
tmp = [s.strip() for s in pkgs.split(",")]
pkgs = ",".join(tmp)
filename = file.split(os.sep)[-1]
continue
res = r.search(line)
if res != None:
req = res.group(1)
tmp = [s.strip() for s in req.split("|")]
req = "|".join(tmp)
continue
res = x.search(line)
if res != None:
excl = res.group(1)
tmp = [s.strip() for s in excl.split("|")]
excl = "|".join(tmp)
continue
if modname != "":
return '"%s" "%s" "%s" "%s" "%s" "%s"\n' % (modname, filename, desc, pkgs, req, excl)
print "Module file without \DeclareLyXModule line. "
sys.exit(2)
def checkTeXAllowSpaces():
''' Let's check whether spaces are allowed in TeX file names '''
tex_allows_spaces = 'false'

View File

@ -5862,22 +5862,82 @@ A module must begin with a line like the following:
\begin_layout LyX-Code
#
\backslash
DeclareLyXModule[endnotes.sty]{Adds an endnote inset.}{Endnotes}
DeclareLyXModule[endnotes.sty]{Endnotes}
\end_layout
\begin_layout Standard
The argument in square brackets is optional: It declares any LaTeX packages
on which the module depends.
The two mandatory arguments, in curly brackets, are a short description
of the module and the name of the module, as they should appear in
The mandatory argument, in curly brackets, is the name of the module, as
it should appear in
\family sans
Document\SpecialChar \menuseparator
Settings
\family default
.
LyX uses the name to identify the module, so it should be unique.
\end_layout
\begin_layout Standard
The module declaration should then be followed by lines like the following:
\end_layout
\begin_layout LyX-Code
#DescriptionBegin
\end_layout
\begin_layout LyX-Code
#Adds an endnote command, in addition to footnotes.
\end_layout
\begin_layout LyX-Code
#You will need to add
\backslash
theendnotes in ERT where you
\end_layout
\begin_layout LyX-Code
#want the endnotes to appear.
\end_layout
\begin_layout LyX-Code
#DescriptionEnd
\end_layout
\begin_layout LyX-Code
#Requires: Some Module | Some Other Module
\end_layout
\begin_layout LyX-Code
#Excludes: Bad Module
\end_layout
\begin_layout Standard
The description is used in
\family sans
Document\SpecialChar \menuseparator
Settings
\family default
to provide the user with information about what the module does.
The Requires is used to identify other modules with which this one must
be used; the Excludes line is used to identify modules with which this
one may not be used.
Both are optional, and, as shown, multiple modules should be separated
with the pipe symbol: |.
Note that the required modules are treated disjunctively:
\emph on
at least one
\emph default
of the required modules must be used.
Similarly,
\emph on
no
\emph default
excluded module may be used.
\end_layout
\begin_layout Standard
After creating a new module, you will need to reconfigure and then restart
LyX for it to appear in the menu.
@ -5901,8 +5961,8 @@ OK
It is strongly recommended that you save your work before doing so
\emph default
.
In fact, it is strongly recommended that you not attempt to create or edit
modules while simultaneously working on documents.
In fact, it is strongly recommended that you not attempt to edit modules
while simultaneously working on documents.
Though of course the developers strive to keep LyX stable in such situations,
syntax errors and the like in your module file could cause strange behavior.
\end_layout

View File

@ -1,5 +1,7 @@
#\DeclareLyXModule[braille.sty]{Defines an environment to typeset Braille.}{Braille}
#\DeclareLyXModule[braille.sty]{Braille}
#DescriptionBegin
#Defines an environment to typeset Braille.
#DescriptionEnd
# Author: Uwe Stöhr <uwestoehr@web.de>
Format 6

View File

@ -1,4 +1,8 @@
#\DeclareLyXModule[endnotes.sty]{Adds an endnote command, in addition to footnotes. You will need to add \theendnotes in ERT where you want the endnotes to appear.}{Endnote}
#\DeclareLyXModule[endnotes.sty]{Endnote}
#DescriptionBegin
#Adds an endnote command, in addition to footnotes. You will need to add
#\theendnotes in ERT where you want the endnotes to appear.
#DescriptionEnd
Format 6

View File

@ -1,4 +1,8 @@
#\DeclareLyXModule[endnotes.sty]{Sets all footnotes as endnotes. You will need to add \theendnotes in ERT where you want the endnotes to appear.}{Foot to End}
#\DeclareLyXModule[endnotes.sty]{Foot to End}
#DescriptionBegin
#Sets all footnotes as endnotes. You will need to add \theendnotes
#in ERT where you want the endnotes to appear.
#DescriptionEnd
Format 6

View File

@ -1,4 +1,8 @@
#\DeclareLyXModule{Adds an environment for hanging paragraphs.}{Hanging}
#\DeclareLyXModule{Hanging}
#DescriptionBegin
#Adds an environment for hanging paragraphs.
#DescriptionEnd
#Author: Richard Heck
#Hanging paragraph code adapted from hanging.sty, available at:

View File

@ -1,4 +1,8 @@
#\DeclareLyXModule[covington.sty]{Defines some special environments useful for linguistics (numbered examples, glosses, semantic markup).}{Linguistics}
#\DeclareLyXModule[covington.sty]{Linguistics}
#DescriptionBegin
#Defines some special environments useful for linguistics (numbered examples,
#glosses, semantic markup).
#DescriptionEnd
# Author: Jürgen Spitzmüller <spitz@lyx.org>

View File

@ -1,4 +1,7 @@
#\DeclareLyXModule{Defines some character styles for logical markup: noun, emph, strong, and code.}{Logical Markup}
#\DeclareLyXModule{Logical Markup}
#DescriptionBegin
#Defines some character styles for logical markup: noun, emph, strong, and code.
#DescriptionEnd
# Author : Martin vermeer <martin.vermeer@hut.fi>

View File

@ -1,4 +1,10 @@
#\DeclareLyXModule{Defines theorem environments and the proof environment for use with non-AMS classes, using the extended AMS machinery. The theorems are numbered within sections. NOTE: Only one of the theorem modules should be used at a time.}{Theorems (AMS, By Section)}
#\DeclareLyXModule{Theorems (AMS, By Section)}
#DescriptionBegin
#Defines theorem environments and the proof environment for use with
#non-AMS classes, using the extended AMS machinery. The theorems are
#numbered within sections.
#DescriptionEnd
#Excludes: Theorems (AMS) | Theorems | Theorems (By Chapter) | Theorems (By Section)
# Author: Richard Heck <rgheck@comcast.net>
# Adapted from amsdefs.inc and amsmaths.inc

View File

@ -1,4 +1,10 @@
#\DeclareLyXModule{Defines theorem environments and the proof environment for use with non-AMS classes, using the extended AMS machinery. The theorems are numbered consecutively throughout the document. NOTE: Only one of the theorem modules should be used at a time.}{Theorems (AMS)}
#\DeclareLyXModule{Theorems (AMS)}
#DescriptionBegin
#Defines theorem environments and the proof environment for use with
#non-AMS classes, using the extended AMS machinery. The theorems are
#numbered consecutively throughout the document.
#DescriptionEnd
#Excludes: Theorems (AMS, By Section) | Theorems | Theorems (By Chapter) | Theorems (By Section)
# Author: Richard Heck <rgheck@comcast.net>
# Adapted from amsdefs.inc and amsmaths.inc

View File

@ -1,4 +1,9 @@
#\DeclareLyXModule{Defines some theorem environments for use with non-AMS classes. The theorems are numbered consecutively throughout the document. NOTE: Only one of the theorem modules should be used at a time.}{Theorems}
#\DeclareLyXModule{Theorems}
#DescriptionBegin
#Defines some theorem environments for use with non-AMS classes. The theorems are
#numbered consecutively throughout the document.
#DescriptionEnd
#Excludes: Theorems (AMS, By Section) | Theorems (AMS) | Theorems (By Chapter) | Theorems (By Section)
# Author: Richard Heck <rgheck@comcast.net>
# Adapted from amsmaths.inc

View File

@ -1,4 +1,9 @@
#\DeclareLyXModule{Defines some theorem environments for use with non-AMS classes. The theorems are numbered within chapters of the document. NOTES: This module should therefore be used only with document classes that define a chapter environment. Only one of the theorem modules should be used at a time.}{Theorems (By Chapter)}
#\DeclareLyXModule{Theorems (By Chapter)}
#DescriptionBegin
#Defines some theorem environments for use with non-AMS classes. The theorems are
#numbered by chapter.
#DescriptionEnd
#Excludes: Theorems (AMS, By Section) | Theorems (AMS) | Theorems | Theorems (By Section)
# Author: Richard Heck <rgheck@comcast.net>
# Adapted from amsmaths.inc

View File

@ -1,4 +1,9 @@
#\DeclareLyXModule{Defines some theorem environments for use with non-AMS classes. The theorems are numbered within sections of the document. NOTE: Only one of the theorem modules should be used at a time.}{Theorems (By Section)}
#\DeclareLyXModule{Theorems (By Section)}
#DescriptionBegin
#Defines some theorem environments for use with non-AMS classes. The theorems are
#numbered by section.
#DescriptionEnd
#Excludes: Theorems (AMS, By Section) | Theorems (AMS) | Theorems (By Chapter) | Theorems
# Author: Richard Heck <rgheck@comcast.net>
# Adapted from amsmaths.inc

View File

@ -1421,7 +1421,7 @@ void BufferParams::makeTextClass()
"may not be possible.\n"), from_utf8(modName));
frontend::Alert::warning(_("Package not available"), msg);
}
FileName layout_file = libFileSearch("layouts", lm->filename);
FileName layout_file = libFileSearch("layouts", lm->getFilename());
textClass_->read(layout_file, TextClass::MODULE);
}
}

View File

@ -35,8 +35,11 @@ ModuleList moduleList;
LyXModule::LyXModule(string const & n, string const & f,
string const & d, vector<string> const & p) :
name(n), filename(f), description(d), packageList(p), checked(false)
string const & d, vector<string> const & p,
vector<string> const & r, vector<string> const & e):
name(n), filename(f), description(d),
packageList(p), requiredModules(r), excludedModules(e),
checked(false)
{}
@ -64,7 +67,7 @@ class ModuleSorter
public:
int operator()(LyXModule const & lm1, LyXModule const & lm2) const
{
return lm1.name < lm2.name;
return lm1.getName() < lm2.getName();
}
};
@ -123,17 +126,37 @@ bool ModuleList::load()
//FIXME Add packages
if (!lex.next())
break;
string packages = lex.getString();
LYXERR(Debug::TCLASS, "Packages: " << packages);
string str = lex.getString();
LYXERR(Debug::TCLASS, "Packages: " << str);
vector<string> pkgs;
while (!packages.empty()) {
while (!str.empty()) {
string p;
packages = split(packages, p, ',');
str = split(str, p, ',');
pkgs.push_back(p);
}
if (!lex.next())
break;
str = lex.getString();
LYXERR(Debug::TCLASS, "Required: " << str);
vector<string> req;
while (!str.empty()) {
string p;
str = split(str, p, '|');
req.push_back(p);
}
if (!lex.next())
break;
str = lex.getString();
LYXERR(Debug::TCLASS, "Excluded: " << str);
vector<string> exc;
while (!str.empty()) {
string p;
str = split(str, p, '|');
exc.push_back(p);
}
// This code is run when we have
// modName, fname, desc, and pkgs
addLayoutModule(modName, fname, desc, pkgs);
// modName, fname, desc, pkgs, req, and exc
addLayoutModule(modName, fname, desc, pkgs, req, exc);
} // end switch
} //end while
@ -147,9 +170,10 @@ bool ModuleList::load()
void ModuleList::addLayoutModule(string const & moduleName,
string const & filename, string const & description,
vector<string> const & pkgs)
vector<string> const & pkgs, vector<string> const & req,
vector<string> const & exc)
{
LyXModule lm(moduleName, filename, description, pkgs);
LyXModule lm(moduleName, filename, description, pkgs, req, exc);
modlist_.push_back(lm);
}
@ -182,7 +206,7 @@ LyXModule * ModuleList::operator[](string const & str)
{
LyXModuleList::iterator it = modlist_.begin();
for (; it != modlist_.end(); ++it)
if (it->name == str) {
if (it->getName() == str) {
LyXModule & mod = *it;
return &mod;
}

View File

@ -29,9 +29,28 @@ class LyXModule {
public:
///
LyXModule(std::string const & n, std::string const & f,
std::string const & d, std::vector<std::string> const & p);
std::string const & d, std::vector<std::string> const & p,
std::vector<std::string> const & r,
std::vector<std::string> const & e);
/// whether the required packages are available
bool isAvailable();
///
std::string const & getName() const { return name; }
///
std::string const & getFilename() const { return filename; }
///
std::string const & getDescription() const { return description; }
///
std::vector<std::string> const & getPackageList() const
{ return packageList; }
///
std::vector<std::string> const & getRequiredModules() const
{ return requiredModules; }
/// Modules this one excludes: the list should be treated disjunctively
std::vector<std::string> const & getExcludedModules() const
{ return excludedModules; }
private:
/// what appears in the ui
std::string name;
/// the filename, without any path
@ -40,7 +59,10 @@ public:
std::string description;
/// the LaTeX packages on which this depends, if any (not implemented)
std::vector<std::string> packageList;
private:
/// Modules this one requires: at least one
std::vector<std::string> requiredModules;
/// Modules this one excludes: none of these
std::vector<std::string> excludedModules;
///
bool checked;
///
@ -59,10 +81,6 @@ public:
ModuleList() {}
/// reads the modules from a file generated by configure.py
bool load();
/// add a module to the list
void addLayoutModule(std::string const & name,
std::string const & filename, std::string const & description,
std::vector<std::string> const & packages);
///
LyXModuleList::const_iterator begin() const;
///
@ -79,8 +97,12 @@ public:
private:
/// noncopyable
ModuleList(ModuleList const &);
///
void operator=(ModuleList const &);
/// add a module to the list
void addLayoutModule(std::string const &, std::string const &,
std::string const &, std::vector<std::string> const &,
std::vector<std::string> const &, std::vector<std::string> const &);
///
std::vector<LyXModule> modlist_;
};

View File

@ -134,6 +134,122 @@ vector<pair<string, lyx::docstring> > pagestyles;
namespace lyx {
namespace frontend {
namespace {
vector<string> getRequiredList(string const & modName)
{
LyXModule const * const mod = moduleList[modName];
if (!mod)
return vector<string>(); //empty such thing
return mod->getRequiredModules();
}
vector<string> getExcludedList(string const & modName)
{
LyXModule const * const mod = moduleList[modName];
if (!mod)
return vector<string>(); //empty such thing
return mod->getExcludedModules();
}
docstring getModuleDescription(string const & modName)
{
LyXModule const * const mod = moduleList[modName];
if (!mod)
return _("Module not found!");
return from_ascii(mod->getDescription());
}
vector<string> getPackageList(string const & modName)
{
LyXModule const * const mod = moduleList[modName];
if (!mod)
return vector<string>(); //empty such thing
return mod->getPackageList();
}
bool isModuleAvailable(string const & modName)
{
LyXModule * mod = moduleList[modName];
if (!mod)
return false;
return mod->isAvailable();
}
} //anonymous namespace
ModuleSelMan::ModuleSelMan(
QListView * availableLV,
QListView * selectedLV,
QPushButton * addPB,
QPushButton * delPB,
QPushButton * upPB,
QPushButton * downPB,
QStringListModel * availableModel,
QStringListModel * selectedModel) :
GuiSelectionManager(availableLV, selectedLV, addPB, delPB,
upPB, downPB, availableModel, selectedModel)
{}
void ModuleSelMan::updateAddPB()
{
int const arows = availableLV->model()->rowCount();
QModelIndexList const availSels =
availableLV->selectionModel()->selectedIndexes();
if (arows == 0 || availSels.isEmpty() || isSelected(availSels.first())) {
addPB->setEnabled(false);
return;
}
QModelIndex const & idx = availableLV->selectionModel()->currentIndex();
string const modName = fromqstr(idx.data().toString());
vector<string> reqs = getRequiredList(modName);
vector<string> excl = getExcludedList(modName);
if (reqs.empty() && excl.empty()) {
addPB->setEnabled(true);
return;
}
QStringList const & qsl = selectedModel->stringList();
//Check whether some required module is available
if (!reqs.empty()) {
bool foundOne = false;
vector<string>::const_iterator it = reqs.begin();
vector<string>::const_iterator end = reqs.end();
for (; it != end; ++it) {
if (qsl.contains(toqstr(*it))) {
foundOne = true;
break;
}
}
if (!foundOne) {
addPB->setEnabled(false);
return;
}
}
//Check whether any excluded module is being used
if (!excl.empty()) {
vector<string>::const_iterator it = excl.begin();
vector<string>::const_iterator end = excl.end();
for (; it != end; ++it) {
if (qsl.contains(toqstr(*it))) {
addPB->setEnabled(false);
return;
}
}
}
addPB->setEnabled(true);
}
/////////////////////////////////////////////////////////////////////
//
// PreambleModule
@ -566,7 +682,7 @@ GuiDocument::GuiDocument(GuiView & lv)
this, SLOT(classChanged()));
selectionManager =
new GuiSelectionManager(latexModule->availableLV, latexModule->selectedLV,
new ModuleSelMan(latexModule->availableLV, latexModule->selectedLV,
latexModule->addPB, latexModule->deletePB,
latexModule->upPB, latexModule->downPB,
availableModel(), selectedModel());
@ -920,46 +1036,77 @@ void GuiDocument::classChanged()
}
namespace {
//This is an insanely complicated attempt to make this sort of thing
//work with RTL languages.
docstring formatStrVec(vector<string> const & v, docstring const & s)
{
//this mess formats the list as "v[0], v[1], ..., [s] v[n]"
int const vSize = v.size();
if (v.size() == 0)
return docstring();
else if (v.size() == 1)
return from_ascii(v[0]);
else if (v.size() == 2) {
docstring retval = _("%1$s and %2$s");
retval = subst(retval, _("and"), s);
return bformat(retval, from_ascii(v[0]), from_ascii(v[1]));
}
//The idea here is to format all but the last two items...
docstring t2 = _("%1$s, %2$s");
docstring retval = from_ascii(v[0]);
for (int i = 1; i < vSize - 2; ++i)
retval = bformat(t2, retval, from_ascii(v[i]));
//...and then to plug them, and the last two, into this schema
docstring t = _("%1$s, %2$s, and %3$s");
t = subst(t, _("and"), s);
return bformat(t, retval, from_ascii(v[vSize - 2]), from_ascii(v[vSize - 1]));
}
}
void GuiDocument::updateModuleInfo()
{
selectionManager->update();
//Module description
QListView const * const lv = selectionManager->selectedFocused() ?
latexModule->selectedLV :
latexModule->availableLV;
latexModule->availableLV;
if (lv->selectionModel()->selectedIndexes().isEmpty())
latexModule->infoML->document()->clear();
else {
QModelIndex const idx = lv->selectionModel()->currentIndex();
QModelIndex const & idx = lv->selectionModel()->currentIndex();
string const modName = fromqstr(idx.data().toString());
string desc = getModuleDescription(modName);
docstring desc = getModuleDescription(modName);
vector<string> pkgList = getPackageList(modName);
string pkgdesc;
//this mess formats the package list as "pkg1, pkg2, and pkg3"
int const pkgListSize = pkgList.size();
for (int i = 0; i < pkgListSize; ++i) {
if (i == 1) {
if (i == pkgListSize - 1) //last element
pkgdesc += " and ";
else
pkgdesc += ", ";
} else if (i > 1) {
if (i == pkgListSize - 1) //last element
pkgdesc += ", and ";
else
pkgdesc += ", ";
}
pkgdesc += pkgList[i];
}
docstring pkgdesc = formatStrVec(pkgList, _("and"));
if (!pkgdesc.empty()) {
if (!desc.empty())
desc += " ";
desc += ("Requires " + pkgdesc + ".");
desc += "\n";
desc += bformat(_("Package(s) required: %1$s."), pkgdesc);
}
pkgList = getRequiredList(modName);
pkgdesc = formatStrVec(pkgList, _("or"));
if (!pkgdesc.empty()) {
if (!desc.empty())
desc += "\n";
desc += bformat(_("Module required: %1$s."), pkgdesc);
}
pkgList = getExcludedList(modName);
pkgdesc = formatStrVec(pkgList, _( "and"));
if (!pkgdesc.empty()) {
if (!desc.empty())
desc += "\n";
desc += bformat(_("Modules excluded: %1$s."), pkgdesc);
}
if (!isModuleAvailable(modName)) {
if (!desc.empty())
desc += "\n";
desc += "WARNING: Some packages are unavailable!";
desc += _("WARNING: Some packages are unavailable!");
}
latexModule->infoML->document()->setPlainText(toqstr(desc));
}
@ -1631,6 +1778,10 @@ void GuiDocument::updateContents()
it = selMods.begin();
for (; it != selMods.end(); ++it)
strlist2.push_back(toqstr(*it));
//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
//at least pop up a warning.
selected_model_.setStringList(strlist2);
updateParams(bp_);
@ -1680,7 +1831,7 @@ BufferId GuiDocument::id() const
}
vector<string> GuiDocument::getModuleNames()
vector<string> const & GuiDocument::getModuleNames()
{
return moduleNames_;
}
@ -1692,33 +1843,6 @@ vector<string> const & GuiDocument::getSelectedModules()
}
string GuiDocument::getModuleDescription(string const & modName) const
{
LyXModule const * const mod = moduleList[modName];
if (!mod)
return string("Module not found!");
return mod->description;
}
vector<string> GuiDocument::getPackageList(string const & modName) const
{
LyXModule const * const mod = moduleList[modName];
if (!mod)
return vector<string>(); //empty such thing
return mod->packageList;
}
bool GuiDocument::isModuleAvailable(string const & modName) const
{
LyXModule * mod = moduleList[modName];
if (!mod)
return false;
return mod->isAvailable();
}
TextClass const & GuiDocument::textClass() const
{
return textclasslist[bp_.getBaseClass()];
@ -1840,7 +1964,7 @@ void GuiDocument::loadModuleNames ()
moduleNames_.clear();
LyXModuleList::const_iterator it = moduleList.begin();
for (; it != moduleList.end(); ++it)
moduleNames_.push_back(it->name);
moduleNames_.push_back(it->getName());
if (!moduleNames_.empty())
sort(moduleNames_.begin(), moduleNames_.end());
}

View File

@ -67,6 +67,24 @@ public:
};
class ModuleSelMan : public GuiSelectionManager
{
public:
ModuleSelMan(
QListView * availableLV,
QListView * selectedLV,
QPushButton * addPB,
QPushButton * delPB,
QPushButton * upPB,
QPushButton * downPB,
QStringListModel * availableModel,
QStringListModel * selectedModel);
private:
///
virtual void updateAddPB();
};
class GuiDocument : public GuiDialog, public Ui::DocumentUi
{
Q_OBJECT
@ -178,16 +196,10 @@ protected:
///
BufferId id() const;
/// List of available modules
std::vector<std::string> getModuleNames();
std::vector<std::string> const & getModuleNames();
/// Modules in use in current buffer
std::vector<std::string> const & getSelectedModules();
///
std::string getModuleDescription(std::string const & modName) const;
///
std::vector<std::string> getPackageList(std::string const & modName) const;
///
bool isModuleAvailable(std::string const & modName) const;
///
void setLanguage() const;
///
void saveAsDefault() const;

View File

@ -68,6 +68,15 @@ GuiSelectionManager::GuiSelectionManager(
void GuiSelectionManager::update()
{
updateAddPB();
updateDelPB();
updateDownPB();
updateUpPB();
}
void GuiSelectionManager::updateAddPB()
{
int const arows = availableLV->model()->rowCount();
QModelIndexList const availSels =
@ -75,17 +84,38 @@ void GuiSelectionManager::update()
addPB->setEnabled(arows > 0 &&
!availSels.isEmpty() &&
!isSelected(availSels.first()));
}
void GuiSelectionManager::updateDelPB()
{
int const srows = selectedLV->model()->rowCount();
QModelIndexList const selSels =
selectedLV->selectionModel()->selectedIndexes();
int const sel_nr = selSels.empty() ? -1 : selSels.first().row();
deletePB->setEnabled(sel_nr >= 0);
upPB->setEnabled(sel_nr > 0);
downPB->setEnabled(sel_nr >= 0 && sel_nr < srows - 1);
}
void GuiSelectionManager::updateDownPB()
{
int const srows = selectedLV->model()->rowCount();
QModelIndexList const selSels =
selectedLV->selectionModel()->selectedIndexes();
int const sel_nr = selSels.empty() ? -1 : selSels.first().row();
upPB->setEnabled(sel_nr > 0);
}
void GuiSelectionManager::updateUpPB()
{
int const srows = selectedLV->model()->rowCount();
QModelIndexList const selSels =
selectedLV->selectionModel()->selectedIndexes();
int const sel_nr = selSels.empty() ? -1 : selSels.first().row();
downPB->setEnabled(sel_nr >= 0 && sel_nr < srows - 1);
}
bool GuiSelectionManager::isSelected(const QModelIndex & idx)
{
QString const str = idx.data().toString();
@ -211,7 +241,7 @@ void GuiSelectionManager::availableLV_clicked(const QModelIndex &)
void GuiSelectionManager::availableLV_doubleClicked(const QModelIndex & idx)
{
if (isSelected(idx))
if (isSelected(idx) || !addPB->isEnabled())
return;
if (idx.isValid())

View File

@ -50,6 +50,8 @@ public:
/// Sets the state of the various push buttons, depending upon the
/// state of the widgets. (E.g., "delete" is enabled only if the
/// selection is non-empty.)
/// Note: this is separated out into updateAddPB(), etc, below,
/// for easy over-riding of these functions.
void update();
/// Not strictly a matter of focus, which may be elsewhere, but
@ -79,6 +81,22 @@ protected:
///Given a QModelIndex from availableLV, determines whether it has
///been selected (i.e., is also in selectedLV).
bool isSelected(const QModelIndex & idx);
///
QListView * availableLV;
///
QListView * selectedLV;
///
QPushButton * addPB;
///
QPushButton * deletePB;
///
QPushButton * upPB;
///
QPushButton * downPB;
///
QStringListModel * availableModel;
///
QStringListModel * selectedModel;
protected Q_SLOTS:
///
@ -103,15 +121,14 @@ protected Q_SLOTS:
bool eventFilter(QObject *, QEvent *);
private:
QListView * availableLV;
QListView * selectedLV;
QPushButton * addPB;
QPushButton * deletePB;
QPushButton * upPB;
QPushButton * downPB;
QStringListModel * availableModel;
QStringListModel * selectedModel;
//Dialog::View * dialog;
///
virtual void updateAddPB();
///
virtual void updateDelPB();
///
virtual void updateDownPB();
///
virtual void updateUpPB();
bool selectedHasFocus_;
};