mirror of
https://git.lyx.org/repos/lyx.git
synced 2024-12-24 21:55:29 +00:00
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:
parent
e975835530
commit
7c28905b17
@ -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'
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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_;
|
||||
};
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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())
|
||||
|
@ -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_;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user