This commit changes the way individual LyXModule's are represented, both internally and in the .lyx files. The earlier version represented them by their `descriptive name', e.g., "Endnote" or "Theorems (AMS)", these being the same names used in the UI. This was a mistake, as becomes readily apparent when one starts to think about translating these strings. The modules ought to be represented by their filename, without the extension, just as TextClass's are.

The changes that accomplish this part are in ModuleList.{h,cpp}, configure.py, and the *.module files themselves. This is a format change, and the lyx2lyx is in those files.

By itself, that change would not be major, except for the fact that we do not want the module to be represented in the UI by its filename---e.g., theorems-std---but rather by a descriptive name, such as "Theorems". But that change turns out to be wholly non-trivial. The mechanism for choosing modules was the same as---indeed, was borrowed from---that in GuiCitation: You get a list of modules, and choosing them involves moving strings from one QListView to another. The models underlying these views are just QStringListModels, which means that, when you want to know what modules have been selected, you see what strings are in the "selected" QListView. But these are just the descriptive names, and we can't look up a module by its descriptive name if it's been translated. That, indeed, was the whole point of the change to the new representation.

So, we need a more complicated model underlying the QListView, one that will pair an identifying string---the filename minus the extension, in this case---with each item. This turns out not to be terribly difficult, though it took rather a while for me to understand why it's not difficult. There are two parts:
(i)  GuiSelectionManger gets re-written to use any QAbstractListModel, not just a QStringListModel. This actually seems to improve the code, independently.
(ii) We then subclass QAbstractListModel to get the associated ID string, using the Qt::UserRole slot associated with each item to store its ID. This would be almost completely trivial if QAbstractListItem::itemData() included the QVariant associated with this role, but it doesn't, so there are some additional hoops through which to jump.

The new model, a GuiIdListModel, is defined in the files by that name. The changes in GuiSelectionManger.{h,cpp} make it more abstract; the changes in GuiDocument.{h,cpp} adapt it to the new framework. 

I've also updated the module documenation to accord with this change.


git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@22501 a592a061-630c-0410-9148-cb99ea01b6c8
This commit is contained in:
Richard Heck 2008-01-12 04:28:12 +00:00
parent 471cf26b11
commit d5d665482e
20 changed files with 440 additions and 212 deletions

View File

@ -1,11 +1,14 @@
LyX file-format changes
-----------------------
2008-01-12 Richard Heck <rgheck@comcast.net>
* Format incremented to 313: change in how modules are represented
2008-01-11 Jürgen Spitzmüller <j.spitzmueller@gmx.de>
* Format incremented to 312: support for sidewaysalgorithm (rotfloat)
and wide sideways{figure,table}.
2008-01-10 Richard Heck <rgheck@bobjweil.com>
2008-01-10 Richard Heck <rgheck@comcast.net>
* Format incremented to 311: dummy format to drive the AMS conversion
2007-12-28 Bernhard Reiter <ockham@gmx.net>

View File

@ -730,6 +730,7 @@ src_frontends_qt4_header_files = Split('''
GuiGraphics.h
GuiGraphicsUi.h
GuiHyperlink.h
GuiIdListModel.h
GuiImage.h
GuiInclude.h
GuiIndex.h
@ -818,6 +819,7 @@ src_frontends_qt4_files = Split('''
GuiFontMetrics.cpp
GuiGraphics.cpp
GuiHyperlink.cpp
GuiIdListModel.cpp
GuiImage.cpp
GuiInclude.cpp
GuiIndex.cpp

View File

@ -754,6 +754,8 @@ def processModuleFile(file, bool_docbook, bool_linuxdoc):
modname = desc = pkgs = req = excl = ""
readingDescription = False
descLines = []
filename = file.split(os.sep)[-1]
filename = filename[:-7]
for line in open(file).readlines():
if readingDescription:
@ -776,8 +778,6 @@ def processModuleFile(file, bool_docbook, bool_linuxdoc):
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:

View File

@ -1,5 +1,5 @@
#LyX 1.6.0svn created this file. For more info see http://www.lyx.org/
\lyxformat 310
\lyxformat 313
\begin_document
\begin_header
\textclass book
@ -58,7 +58,7 @@
\usepackage{multicol}
\end_preamble
\begin_modules
Logical Markup
logicalmkup
\end_modules
\language english
\inputencoding default
@ -5907,11 +5907,11 @@ theendnotes in ERT where you
\end_layout
\begin_layout LyX-Code
#Requires: Some Module | Some Other Module
#Requires: somemodule | othermodule
\end_layout
\begin_layout LyX-Code
#Excludes: Bad Module
#Excludes: badmodule
\end_layout
\begin_layout Standard
@ -5936,6 +5936,32 @@ at least one
no
\emph default
excluded module may be used.
Note that modules are identified here by their
\emph on
filenames
\emph default
without the .module extension.
So
\begin_inset Flex CharStyle:Code
status collapsed
\begin_layout Standard
somemodule
\end_layout
\end_inset
is really
\begin_inset Flex CharStyle:Code
status collapsed
\begin_layout Standard
somemodule.module
\end_layout
\end_inset
.
\end_layout
\begin_layout Standard
@ -5947,7 +5973,7 @@ After creating a new module, you will need to reconfigure and then restart
Document\SpecialChar \menuseparator
Settings
\family default
, make some change (or even just highlight something), and then hit
, highlight something, and then hit
\begin_inset Quotes eld
\end_inset

View File

@ -5,7 +5,7 @@
#Condition, Note, Notation, Summary, Acknowledgement, Conclusion,
#Fact, Assumption, and Case, in both starred and non-starred forms.
#DescriptionEnd
#Requires: Theorems (AMS)
#Requires: theorems-ams
# Original Author : David L. Johnson <dlj0@lehigh.edu>
# Probably broken by Jean-Marc Lasgouttes <Jean-Marc.Lasgouttes@inria.fr>

View File

@ -5,7 +5,7 @@
#the theorems are numbered consecutively throughout the document. This can be
#changed by loading one of the Theorems (Ordered By ...) modules.
#DescriptionEnd
#Excludes: Theorems | Theorems (Starred)
#Excludes: theorems-std | theorems-starred
# Original Author : David L. Johnson <dlj0@lehigh.edu>
# Probably broken by Jean-Marc Lasgouttes <Jean-Marc.Lasgouttes@inria.fr>

View File

@ -2,7 +2,7 @@
#DescriptionBegin
#Numbers theorems and the like by chapter.
#DescriptionEnd
#Requires: Theorems | Theorems (AMS)
#Requires: theorems-std | theorems-ams
# Author: Richard Heck <rgheck@comcast.net>

View File

@ -2,7 +2,7 @@
#DescriptionBegin
#Numbers theorems and the like by section.
#DescriptionEnd
#Requires: Theorems | Theorems (AMS)
#Requires: theorems-std | theorems-ams
# Author: Richard Heck <rgheck@comcast.net>

View File

@ -3,7 +3,7 @@
#Defines only unnumbered theorem environments, and the proof environment, using
#the extended AMS machinery.
##DescriptionEnd
#Excludes: Theorems (AMS) | Theorems (Starred) | Theorems (Order By Section) | Theorems (Order By Chapter)
#Excludes: theorems-std | theorems-ams
# Author: Richard Heck <rgheck@comcast.net>

View File

@ -4,7 +4,7 @@
#the theorems are numbered consecutively throughout the document. This can be
#changed by loading one of the Theorems (Ordered By ...) modules.
#DescriptionEnd
#Excludes: Theorems (AMS) | Theorems (Starred)
#Excludes: theorems-ams | theorems-starred
# Author: Richard Heck <rgheck@comcast.net>

View File

@ -80,7 +80,7 @@ format_relation = [("0_06", [200], minor_versions("0.6" , 4)),
("1_3", [221], minor_versions("1.3" , 7)),
("1_4", range(222,246), minor_versions("1.4" , 5)),
("1_5", range(246,277), minor_versions("1.5" , 2)),
("1_6", range(277,313), minor_versions("1.6" , 0))] # JSpitzm: rotfloat support
("1_6", range(277,314), minor_versions("1.6" , 0))] # Richard Heck: conversion of module representations
def formats_list():
@ -412,6 +412,30 @@ class LyX_base:
self.header.insert(j, module)
def get_module_list(self):
i = find_token(self.header, "\\begin_modules", 0)
if (i == -1):
return []
j = find_token(self.header, "\\end_modules", i)
return self.header[i + 1 : j]
def set_module_list(self, mlist):
modbegin = find_token(self.header, "\\begin_modules", 0)
if (modbegin == -1):
#No modules yet included
modbegin = find_token(self.header, "\\textclass", 0)
if modbegin == -1:
self.warning("Malformed LyX document: No \\textclass!!")
return
modend = find_token(self.header, "\\end_modules", modbegin)
if modend == -1:
self.warning("Malformed LyX document: No \\end_modules.")
return
newmodlist = ['\\begin_modules'] + mlist + ['\\end_modules']
self.header[modbegin:modend + 1] = newmodlist
def set_parameter(self, param, value):
" Set the value of the header parameter."
i = find_token(self.header, '\\' + param, 0)

View File

@ -922,6 +922,40 @@ def convert_framed_notes(document):
i = i + 1
def convert_module_names(document):
modulemap = { 'Braille' : 'braille', 'Endnote' : 'endnotes', 'Foot to End' : 'foottoend',\
'Hanging' : 'hanging', 'Linguistics' : 'linguistics', 'Logical Markup' : 'logicalmkup', \
'Theorems (AMS-Extended)' : 'theorems-ams-extended', 'Theorems (AMS)' : 'theorems-ams', \
'Theorems (Order By Chapter)' : 'theorems-chap', 'Theorems (Order By Section)' : 'theorems-sec', \
'Theorems (Starred)' : 'theorems-starred', 'Theorems' : 'theorems-std' }
modlist = document.get_module_list()
newmodlist = []
for mod in modlist:
if modulemap.has_key(mod):
newmodlist.append(modulemap[mod])
else:
document.warning("Can't find module %s in the module map!" % mod)
newmodlist.append(mod)
document.set_module_list(newmodlist)
def revert_module_names(document):
modulemap = { 'braille' : 'Braille', 'endnotes' : 'Endnote', 'foottoend' : 'Foot to End',\
'hanging' : 'Hanging', 'linguistics' : 'Linguistics', 'logicalmkup' : 'Logical Markup', \
'theorems-ams-extended' : 'Theorems (AMS-Extended)', 'theorems-ams' : 'Theorems (AMS)', \
'theorems-chap' : 'Theorems (Order By Chapter)', 'theorems-sec' : 'Theorems (Order By Section)', \
'theorems-starred' : 'Theorems (Starred)', 'theorems-std' : 'Theorems'}
modlist = document.get_module_list()
newmodlist = []
for mod in modlist:
if modulemap.has_key(mod):
newmodlist.append(modulemap[mod])
else:
document.warning("Can't find module %s in the module map!" % mod)
newmodlist.append(mod)
document.set_module_list(newmodlist)
def revert_framed_notes(document):
"Revert framed boxes to notes. "
i = 0
@ -1213,9 +1247,11 @@ convert = [[277, [fix_wrong_tables]],
[310, []],
[311, [convert_ams_classes]],
[312, []],
[313, [convert_module_names]]
]
revert = [[311, [revert_rotfloat, revert_widesideways]],
revert = [[312, [revert_module_names]],
[311, [revert_rotfloat, revert_widesideways]],
[310, []],
[309, [revert_btprintall]],
[308, [revert_nocite]],

View File

@ -118,7 +118,7 @@ namespace os = support::os;
namespace {
int const LYX_FORMAT = 312; // JSpitzm: rotfloat support
int const LYX_FORMAT = 313; // Richard Heck: conversion of module representations
} // namespace anon

View File

@ -34,13 +34,15 @@ namespace lyx {
ModuleList moduleList;
LyXModule::LyXModule(string const & n, string const & f,
LyXModule::LyXModule(string const & n, string const & i,
string const & d, vector<string> const & p,
vector<string> const & r, vector<string> const & e):
name(n), filename(f), description(d),
name(n), id(i), description(d),
packageList(p), requiredModules(r), excludedModules(e),
checked(false)
{}
{
filename = id + ".module";
}
bool LyXModule::isAvailable() {
@ -204,7 +206,7 @@ LyXModuleList::iterator ModuleList::end()
}
LyXModule * ModuleList::operator[](string const & str)
LyXModule * ModuleList::getModuleByName(string const & str)
{
LyXModuleList::iterator it = modlist_.begin();
for (; it != modlist_.end(); ++it)
@ -215,4 +217,15 @@ LyXModule * ModuleList::operator[](string const & str)
return 0;
}
LyXModule * ModuleList::operator[](string const & str)
{
LyXModuleList::iterator it = modlist_.begin();
for (; it != modlist_.end(); ++it)
if (it->getID() == str) {
LyXModule & mod = *it;
return &mod;
}
return 0;
}
} // namespace lyx

View File

@ -28,7 +28,7 @@ namespace lyx {
class LyXModule {
public:
///
LyXModule(std::string const & n, std::string const & f,
LyXModule(std::string const & n, std::string const & i,
std::string const & d, std::vector<std::string> const & p,
std::vector<std::string> const & r,
std::vector<std::string> const & e);
@ -37,6 +37,8 @@ public:
///
std::string const & getName() const { return name; }
///
std::string const & getID() const { return id; }
///
std::string const & getFilename() const { return filename; }
///
std::string const & getDescription() const { return description; }
@ -53,7 +55,10 @@ public:
private:
/// what appears in the ui
std::string name;
/// the filename, without any path
/// the module's unique identifier
/// at present, this is the filename, without the extension
std::string id;
/// the filename
std::string filename;
/// a short description for use in the ui
std::string description;
@ -93,8 +98,11 @@ public:
bool empty() const { return modlist_.empty(); }
/// Returns a pointer to the LyXModule with name str.
/// Returns a null pointer if no such module is found.
LyXModule * getModuleByName(std::string const & str);
/// Returns a pointer to the LyXModule with filename str.
/// Returns a null pointer if no such module is found.
LyXModule * operator[](std::string const & str);
private:
private:
/// noncopyable
ModuleList(ModuleList const &);
///

View File

@ -189,16 +189,29 @@ ModuleSelMan::ModuleSelMan(
QPushButton * delPB,
QPushButton * upPB,
QPushButton * downPB,
QStringListModel * availableModel,
QStringListModel * selectedModel) :
GuiIdListModel * availableModel,
GuiIdListModel * selectedModel) :
GuiSelectionManager(availableLV, selectedLV, addPB, delPB,
upPB, downPB, availableModel, selectedModel)
{}
namespace {
QModelIndex getSelectedIndex(QListView * lv)
{
QModelIndex retval = QModelIndex();
QModelIndexList selIdx =
lv->selectionModel()->selectedIndexes();
if (!selIdx.empty())
retval = selIdx.first();
return retval;
}
}
void ModuleSelMan::updateAddPB()
{
int const arows = availableModel->stringList().size();
int const arows = availableModel->rowCount();
QModelIndexList const availSels =
availableLV->selectionModel()->selectedIndexes();
if (arows == 0 || availSels.isEmpty() || isSelected(availSels.first())) {
@ -207,7 +220,7 @@ void ModuleSelMan::updateAddPB()
}
QModelIndex const & idx = availableLV->selectionModel()->currentIndex();
string const modName = fromqstr(idx.data().toString());
string const modName = getAvailableModel()->getIDString(idx.row());
vector<string> reqs = getRequiredList(modName);
vector<string> excl = getExcludedList(modName);
@ -216,7 +229,13 @@ void ModuleSelMan::updateAddPB()
return;
}
QStringList const & qsl = selectedModel->stringList();
int const srows = selectedModel->rowCount();
vector<string> selModList;
for (int i = 0; i < srows; ++i)
selModList.push_back(getSelectedModel()->getIDString(i));
vector<string>::const_iterator selModStart = selModList.begin();
vector<string>::const_iterator selModEnd = selModList.end();
//Check whether some required module is available
if (!reqs.empty()) {
@ -224,7 +243,7 @@ void ModuleSelMan::updateAddPB()
vector<string>::const_iterator it = reqs.begin();
vector<string>::const_iterator end = reqs.end();
for (; it != end; ++it) {
if (qsl.contains(toqstr(*it))) {
if (find(selModStart, selModEnd, *it) != selModEnd) {
foundOne = true;
break;
}
@ -240,7 +259,7 @@ void ModuleSelMan::updateAddPB()
vector<string>::const_iterator it = excl.begin();
vector<string>::const_iterator end = excl.end();
for (; it != end; ++it) {
if (qsl.contains(toqstr(*it))) {
if (find(selModStart, selModEnd, *it) != selModEnd) {
addPB->setEnabled(false);
return;
}
@ -250,9 +269,10 @@ void ModuleSelMan::updateAddPB()
addPB->setEnabled(true);
}
void ModuleSelMan::updateDownPB()
{
int const srows = selectedModel->stringList().size();
int const srows = selectedModel->rowCount();
if (srows == 0) {
downPB->setEnabled(false);
return;
@ -265,15 +285,14 @@ void ModuleSelMan::updateDownPB()
return;
}
//determine whether immediately succeding element requires this one
QString const curModName =
selectedLV->selectionModel()->currentIndex().data().toString();
QStringList const & qsl = selectedModel->stringList();
int const curIdx = qsl.indexOf(curModName);
if (curIdx < 0 || curIdx == srows - 1) { //this shouldn't happen...
QModelIndex const & curIdx = selectedLV->selectionModel()->currentIndex();
int curRow = curIdx.row();
if (curRow < 0 || curRow >= srows - 1) { //this shouldn't happen...
downPB->setEnabled(false);
return;
}
string nextModName = fromqstr(qsl[curIdx + 1]);
string const curModName = getSelectedModel()->getIDString(curRow);
string const nextModName = getSelectedModel()->getIDString(curRow + 1);
vector<string> reqs = getRequiredList(nextModName);
@ -287,12 +306,12 @@ void ModuleSelMan::updateDownPB()
//if this one is required, there is also an earlier one that is required.
//enable it if this module isn't required
downPB->setEnabled(
find(reqs.begin(), reqs.end(), fromqstr(curModName)) == reqs.end());
find(reqs.begin(), reqs.end(), curModName) == reqs.end());
}
void ModuleSelMan::updateUpPB()
{
int const srows = selectedModel->stringList().size();
int const srows = selectedModel->rowCount();
if (srows == 0) {
upPB->setEnabled(false);
return;
@ -304,10 +323,16 @@ void ModuleSelMan::updateUpPB()
upPB->setEnabled(false);
return;
}
//determine whether immediately preceding element is required by this one
QString const curModName =
selectedLV->selectionModel()->currentIndex().data().toString();
vector<string> reqs = getRequiredList(fromqstr(curModName));
QModelIndex const & curIdx = selectedLV->selectionModel()->currentIndex();
int curRow = curIdx.row();
if (curRow <= -1 || curRow > srows - 1) { //sanity check
downPB->setEnabled(false);
return;
}
string const curModName = getSelectedModel()->getIDString(curRow);
vector<string> reqs = getRequiredList(curModName);
//if this one doesn't require anything....
if (reqs.empty()) {
@ -315,13 +340,7 @@ void ModuleSelMan::updateUpPB()
return;
}
QStringList const & qsl = selectedModel->stringList();
int const curIdx = qsl.indexOf(curModName);
if (curIdx <= 0) { //this shouldn't happen...
upPB->setEnabled(false);
return;
}
string preModName = fromqstr(qsl[curIdx - 1]);
string preModName = getSelectedModel()->getIDString(curRow - 1);
//NOTE This is less flexible than it might be. You could check whether, even
//if this one is required, there is also an earlier one that is required.
@ -331,7 +350,7 @@ void ModuleSelMan::updateUpPB()
void ModuleSelMan::updateDelPB()
{
int const srows = selectedModel->stringList().size();
int const srows = selectedModel->rowCount();
if (srows == 0) {
deletePB->setEnabled(false);
return;
@ -346,59 +365,49 @@ void ModuleSelMan::updateDelPB()
//determine whether some LATER module requires this one
//NOTE Things are arranged so that this is the only way there
//can be a problem. At least, we hope so.
QString const curModName =
selectedLV->selectionModel()->currentIndex().data().toString();
QStringList const & qsl = selectedModel->stringList();
QModelIndex const & curIdx =
selectedLV->selectionModel()->currentIndex();
int const curRow = curIdx.row();
if (curRow < 0 || curRow >= srows) { //this shouldn't happen
deletePB->setEnabled(false);
return;
}
QString const curModName = curIdx.data().toString();
//We're looking here for a reason NOT to enable the button. If we
//find one, we disable it and return. If we don't, we'll end up at
//the end of the function, and then we enable it.
QStringList::const_iterator it = qsl.begin();
QStringList::const_iterator end = qsl.end();
bool found = false;
for (; it != end; ++it) {
//skip over the ones preceding this one
if (!found) {
if (*it == curModName) {
found = true;
}
continue;
}
string const mod = fromqstr(*it);
vector<string> reqs = getRequiredList(mod);
for (int i = curRow + 1; i < srows; ++i) {
string const thisMod = getSelectedModel()->getIDString(i);
vector<string> reqs = getRequiredList(thisMod);
//does this one require us?
if (find(reqs.begin(), reqs.end(), fromqstr(curModName)) == reqs.end())
//no...
continue;
//OK, so there is a module that requires us
//is there an EARLIER module that satisfies the require?
//OK, so this module requires us
//is there an EARLIER module that also satisfies the require?
//NOTE We demand that it be earlier to keep the list of modules
//consistent with the rule that a module must be proceeded by a
//required module. There would be more flexible ways to proceed,
//but that would be a lot more complicated, and the logic here is
//already complicated. (That's why I've left the debugging code.)
//lyxerr << "Testing " << mod << std::endl;
QStringList::const_iterator it2 = qsl.begin();
QStringList::const_iterator end2 = qsl.end();
for (; it2 != end2; ++it2) {
//lyxerr << "In loop: Testing " << fromqstr(*it2) << std::endl;
if (*it2 == curModName) { //EARLIER!!
//no other module was found before this one, so...
//lyxerr << "Reached the end of the loop." << std::endl;
deletePB->setEnabled(false);
return;
}
//lyxerr << "Testing " << thisMod << std::endl;
bool foundOne = false;
for (int j = 0; j < curRow; ++j) {
string const mod = getSelectedModel()->getIDString(j);
//lyxerr << "In loop: Testing " << mod << std::endl;
//do we satisfy the require?
if (find(reqs.begin(), reqs.end(), fromqstr(*it2)) != reqs.end()) {
//lyxerr << fromqstr(*it2) << " does the trick." << std::endl;
if (find(reqs.begin(), reqs.end(), mod) != reqs.end()) {
//lyxerr << mod << " does the trick." << std::endl;
foundOne = true;
break;
}
}
//did we reach the end of the list?
if (it2 == end2) {
//lyxerr << "Reached end of list." << std::endl;
//did we find a module to satisfy the require?
if (!foundOne) {
//lyxerr << "No matching module found." << std::endl;
deletePB->setEnabled(false);
return;
}
@ -1221,54 +1230,75 @@ namespace {
t = subst(t, _("and"), s);
return bformat(t, retval, from_ascii(v[vSize - 2]), from_ascii(v[vSize - 1]));
}
vector<string> idsToNames(vector<string> const & idList)
{
vector<string> retval;
vector<string>::const_iterator it = idList.begin();
vector<string>::const_iterator end = idList.end();
for (; it != end; ++it) {
LyXModule const * const mod = moduleList[*it];
if (!mod)
retval.push_back(*it + " (Unavailable)");
else
retval.push_back(mod->getName());
}
return retval;
}
}
void GuiDocument::updateModuleInfo()
{
selectionManager->update();
//Module description
QListView const * const lv = selectionManager->selectedFocused() ?
latexModule->selectedLV :
latexModule->availableLV;
if (lv->selectionModel()->selectedIndexes().isEmpty())
bool const focusOnSelected = selectionManager->selectedFocused();
QListView const * const lv =
focusOnSelected ? latexModule->selectedLV : latexModule->availableLV;
if (lv->selectionModel()->selectedIndexes().isEmpty()) {
latexModule->infoML->document()->clear();
else {
QModelIndex const & idx = lv->selectionModel()->currentIndex();
string const modName = fromqstr(idx.data().toString());
docstring desc = getModuleDescription(modName);
vector<string> pkgList = getPackageList(modName);
docstring pkgdesc = formatStrVec(pkgList, _("and"));
if (!pkgdesc.empty()) {
if (!desc.empty())
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!");
}
latexModule->infoML->document()->setPlainText(toqstr(desc));
return;
}
QModelIndex const & idx = lv->selectionModel()->currentIndex();
GuiIdListModel const & idModel =
focusOnSelected ? selected_model_ : available_model_;
string const modName = idModel.getIDString(idx.row());
docstring desc = getModuleDescription(modName);
vector<string> pkgList = getPackageList(modName);
docstring pkgdesc = formatStrVec(pkgList, _("and"));
if (!pkgdesc.empty()) {
if (!desc.empty())
desc += "\n";
desc += bformat(_("Package(s) required: %1$s."), pkgdesc);
}
pkgList = getRequiredList(modName);
if (!pkgList.empty()) {
vector<string> const reqDescs = idsToNames(pkgList);
pkgdesc = formatStrVec(reqDescs, _("or"));
if (!desc.empty())
desc += "\n";
desc += bformat(_("Module required: %1$s."), pkgdesc);
}
pkgList = getExcludedList(modName);
if (!pkgList.empty()) {
vector<string> const reqDescs = idsToNames(pkgList);
pkgdesc = formatStrVec(reqDescs, _( "and"));
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!");
}
latexModule->infoML->document()->setPlainText(toqstr(desc));
}
@ -1408,9 +1438,10 @@ void GuiDocument::apply(BufferParams & params)
// Modules
params.clearLayoutModules();
QStringList const selMods = selectedModel()->stringList();
for (int i = 0; i != selMods.size(); ++i)
params.addLayoutModule(lyx::fromqstr(selMods[i]));
int const srows = selected_model_.rowCount();
vector<string> selModList;
for (int i = 0; i < srows; ++i)
params.addLayoutModule(selected_model_.getIDString(i));
if (mathsModule->amsautoCB->isChecked()) {
params.use_amsmath = BufferParams::package_auto;
@ -1922,27 +1953,40 @@ void GuiDocument::saveDocDefault()
}
void GuiDocument::updateAvailableModules()
{
available_model_.clear();
vector<modInfoStruct> const modInfoList = getModuleInfo();
int const mSize = modInfoList.size();
for (int i = 0; i < mSize; ++i) {
modInfoStruct const & modInfo = modInfoList[i];
available_model_.insertRow(i, modInfo.name, modInfo.id);
}
}
void GuiDocument::updateSelectedModules()
{
//and selected ones, too
selected_model_.clear();
vector<modInfoStruct> const selModList = getSelectedModules();
int const sSize = selModList.size();
for (int i = 0; i < sSize; ++i) {
modInfoStruct const & modInfo = selModList[i];
selected_model_.insertRow(i, modInfo.name, modInfo.id);
}
}
void GuiDocument::updateContents()
{
//update list of available modules
QStringList strlist;
vector<string> const modNames = getModuleNames();
vector<string>::const_iterator it = modNames.begin();
for (; it != modNames.end(); ++it)
strlist.push_back(toqstr(*it));
available_model_.setStringList(strlist);
//and selected ones, too
QStringList strlist2;
vector<string> const & selMods = getSelectedModules();
it = selMods.begin();
for (; it != selMods.end(); ++it)
strlist2.push_back(toqstr(*it));
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
//at least pop up a warning.
selected_model_.setStringList(strlist2);
updateParams(bp_);
}
@ -1973,7 +2017,7 @@ char const * GuiDocument::fontfamilies_gui[5] = {
bool GuiDocument::initialiseParams(string const &)
{
bp_ = buffer().params();
loadModuleNames();
loadModuleInfo();
return true;
}
@ -1990,15 +2034,29 @@ BufferId GuiDocument::id() const
}
vector<string> const & GuiDocument::getModuleNames()
vector<GuiDocument::modInfoStruct> const & GuiDocument::getModuleInfo()
{
return moduleNames_;
}
vector<string> const & GuiDocument::getSelectedModules()
vector<GuiDocument::modInfoStruct> const GuiDocument::getSelectedModules()
{
return params().getModules();
vector<string> const & mods = params().getModules();
vector<string>::const_iterator it = mods.begin();
vector<string>::const_iterator end = mods.end();
vector<modInfoStruct> mInfo;
for (; it != end; ++it) {
modInfoStruct m;
m.id = *it;
LyXModule * mod = moduleList[*it];
if (mod)
m.name = mod->getName();
else
m.name = *it + " (Not Found)";
mInfo.push_back(m);
}
return mInfo;
}
@ -2118,14 +2176,17 @@ bool GuiDocument::providesScale(string const & font) const
}
void GuiDocument::loadModuleNames ()
void GuiDocument::loadModuleInfo()
{
moduleNames_.clear();
LyXModuleList::const_iterator it = moduleList.begin();
for (; it != moduleList.end(); ++it)
moduleNames_.push_back(it->getName());
if (!moduleNames_.empty())
sort(moduleNames_.begin(), moduleNames_.end());
LyXModuleList::const_iterator it = moduleList.begin();
LyXModuleList::const_iterator end = moduleList.end();
for (; it != end; ++it) {
modInfoStruct m;
m.id = it->getID();
m.name = it->getName();
moduleNames_.push_back(m);
}
}

View File

@ -13,10 +13,13 @@
#ifndef GUIDOCUMENT_H
#define GUIDOCUMENT_H
#include "GuiDialog.h"
#include "BulletsModule.h"
#include "GuiSelectionManager.h"
#include <QDialog>
#include "BufferParams.h"
#include "BulletsModule.h"
#include "GuiDialog.h"
#include "GuiIdListModel.h"
#include "GuiSelectionManager.h"
#include "support/types.h"
@ -52,13 +55,6 @@ class PreambleModule;
///
typedef void const * BufferId;
#include <QDialog>
#include <QStringList>
#include <QStringListModel>
#include <vector>
#include <string>
template<class UI>
class UiWidget : public QWidget, public UI
{
@ -77,8 +73,8 @@ public:
QPushButton * delPB,
QPushButton * upPB,
QPushButton * downPB,
QStringListModel * availableModel,
QStringListModel * selectedModel);
GuiIdListModel * availableModel,
GuiIdListModel * selectedModel);
private:
///
virtual void updateAddPB();
@ -88,6 +84,16 @@ private:
virtual void updateDownPB();
///
virtual void updateDelPB();
/// returns availableModel as a GuiIdListModel
GuiIdListModel * getAvailableModel()
{
return dynamic_cast<GuiIdListModel *>(availableModel);
};
/// returns selectedModel as a GuiIdListModel
GuiIdListModel * getSelectedModel()
{
return dynamic_cast<GuiIdListModel *>(selectedModel);
};
};
@ -158,22 +164,26 @@ private:
std::vector<std::string> lang_;
/// Available modules
QStringListModel * availableModel() { return &available_model_; }
GuiIdListModel * availableModel() { return &available_model_; }
/// Selected modules
QStringListModel * selectedModel() { return &selected_model_; }
GuiIdListModel * selectedModel() { return &selected_model_; }
private:
/// Apply changes
void applyView();
/// update
void updateContents();
///
void updateAvailableModules();
///
void updateSelectedModules();
/// save as default template
void saveDocDefault();
/// reset to default params
void useClassDefaults();
/// available modules
QStringListModel available_model_;
GuiIdListModel available_model_;
/// selected modules
QStringListModel selected_model_;
GuiIdListModel selected_model_;
protected:
/// return false if validate_listings_params returns error
@ -201,10 +211,15 @@ protected:
BufferParams const & params() const { return bp_; }
///
BufferId id() const;
///
struct modInfoStruct {
std::string name;
std::string id;
};
/// List of available modules
std::vector<std::string> const & getModuleNames();
std::vector<modInfoStruct> const & getModuleInfo();
/// Modules in use in current buffer
std::vector<std::string> const & getSelectedModules();
std::vector<modInfoStruct> const getSelectedModules();
///
void setLanguage() const;
///
@ -219,11 +234,11 @@ protected:
bool providesScale(std::string const & font) const;
private:
///
void loadModuleNames();
void loadModuleInfo();
///
BufferParams bp_;
/// List of names of available modules
std::vector<std::string> moduleNames_;
std::vector<modInfoStruct> moduleNames_;
};
@ -256,4 +271,4 @@ private:
} // namespace frontend
} // namespace lyx
#endif // QDOCUMENT_H
#endif // GUIDOCUMENT_H

View File

@ -15,10 +15,14 @@
#include <config.h>
#include "GuiSelectionManager.h"
#include "support/debug.h"
using std::vector;
namespace lyx {
namespace frontend {
GuiSelectionManager::GuiSelectionManager(
QListView * avail,
QListView * sel,
@ -26,8 +30,8 @@ GuiSelectionManager::GuiSelectionManager(
QPushButton * del,
QPushButton * up,
QPushButton * down,
QStringListModel * amod,
QStringListModel * smod)
QAbstractListModel * amod,
QAbstractListModel * smod)
{
availableLV = avail;
selectedLV = sel;
@ -78,7 +82,7 @@ void GuiSelectionManager::update()
void GuiSelectionManager::updateAddPB()
{
int const arows = availableModel->stringList().size();
int const arows = availableModel->rowCount();
QModelIndexList const availSels =
availableLV->selectionModel()->selectedIndexes();
addPB->setEnabled(arows > 0 &&
@ -89,7 +93,7 @@ void GuiSelectionManager::updateAddPB()
void GuiSelectionManager::updateDelPB()
{
int const srows = selectedModel->stringList().size();
int const srows = selectedModel->rowCount();
if (srows == 0) {
deletePB->setEnabled(false);
return;
@ -103,7 +107,7 @@ void GuiSelectionManager::updateDelPB()
void GuiSelectionManager::updateUpPB()
{
int const srows = selectedModel->stringList().size();
int const srows = selectedModel->rowCount();
if (srows == 0) {
upPB->setEnabled(false);
return;
@ -117,7 +121,7 @@ void GuiSelectionManager::updateUpPB()
void GuiSelectionManager::updateDownPB()
{
int const srows = selectedModel->stringList().size();
int const srows = selectedModel->rowCount();
if (srows == 0) {
downPB->setEnabled(false);
return;
@ -128,10 +132,17 @@ void GuiSelectionManager::updateDownPB()
downPB->setEnabled(sel_nr >= 0 && sel_nr < srows - 1);
}
bool GuiSelectionManager::isSelected(const QModelIndex & idx)
{
QString const str = idx.data().toString();
return selectedModel->stringList().contains(str);
if (selectedModel->rowCount() == 0)
return false;
QVariant const & str = availableModel->data(idx, Qt::DisplayRole);
QModelIndexList qmil =
selectedModel->match(selectedModel->index(0),
Qt::DisplayRole, str,
Qt::MatchExactly | Qt::MatchWrap);
return !qmil.empty();
}
@ -155,7 +166,8 @@ void GuiSelectionManager::selectedChanged(const QModelIndex & idx, const QModelI
}
static QModelIndex getSelectedIndex(QListView * lv)
namespace {
QModelIndex getSelectedIndex(QListView * lv)
{
QModelIndex retval = QModelIndex();
QModelIndexList selIdx =
@ -164,6 +176,18 @@ static QModelIndex getSelectedIndex(QListView * lv)
retval = selIdx.first();
return retval;
}
}
bool GuiSelectionManager::insertRowToSelected(int i,
QMap<int, QVariant> const & itemData)
{
if (i <= -1 || i > selectedModel->rowCount())
return false;
if (!selectedModel->insertRow(i))
return false;
return selectedModel->setItemData(selectedModel->index(i), itemData);
}
void GuiSelectionManager::addPB_clicked()
@ -171,15 +195,17 @@ void GuiSelectionManager::addPB_clicked()
QModelIndex const idxToAdd = getSelectedIndex(availableLV);
if (!idxToAdd.isValid())
return;
QModelIndex idx = selectedLV->currentIndex();
QModelIndex const idx = selectedLV->currentIndex();
int const srows = selectedModel->rowCount();
QMap<int, QVariant> qm = availableModel->itemData(idxToAdd);
insertRowToSelected(srows, qm);
QStringList keys = selectedModel->stringList();
keys.append(idxToAdd.data().toString());
selectedModel->setStringList(keys);
selectionChanged(); //signal
if (idx.isValid())
selectedLV->setCurrentIndex(idx);
updateHook();
}
@ -190,9 +216,7 @@ void GuiSelectionManager::deletePB_clicked()
if (!idx.isValid())
return;
QStringList keys = selectedModel->stringList();
keys.removeAt(idx.row());
selectedModel->setStringList(keys);
selectedModel->removeRow(idx.row());
selectionChanged(); //signal
int nrows = selectedLV->model()->rowCount();
@ -211,13 +235,18 @@ void GuiSelectionManager::deletePB_clicked()
void GuiSelectionManager::upPB_clicked()
{
QModelIndex idx = selectedLV->currentIndex();
int const pos = idx.row();
QStringList keys = selectedModel->stringList();
keys.swap(pos, pos - 1);
selectedModel->setStringList(keys);
selectionChanged(); //signal
if (pos <= 0)
return;
QMap<int, QVariant> qm = selectedModel->itemData(idx);
selectedModel->removeRow(pos);
insertRowToSelected(pos - 1, qm);
selectionChanged(); //signal
selectedLV->setCurrentIndex(idx.sibling(idx.row() - 1, idx.column()));
selectedHasFocus_ = true;
updateHook();
@ -227,11 +256,16 @@ void GuiSelectionManager::upPB_clicked()
void GuiSelectionManager::downPB_clicked()
{
QModelIndex idx = selectedLV->currentIndex();
int const pos = idx.row();
QStringList keys = selectedModel->stringList();
keys.swap(pos, pos + 1);
selectedModel->setStringList(keys);
if (pos >= selectedModel->rowCount() - 1)
return;
QMap<int, QVariant> qm = selectedModel->itemData(idx);
selectedModel->removeRow(pos);
insertRowToSelected(pos + 1, qm);
selectionChanged(); //signal
selectedLV->setCurrentIndex(idx.sibling(idx.row() + 1, idx.column()));
@ -311,9 +345,7 @@ bool GuiSelectionManager::eventFilter(QObject * obj, QEvent * event)
if (keyModifiers == Qt::NoModifier && deletePB->isEnabled())
deletePB_clicked();
else if (keyModifiers == Qt::ControlModifier) {
QStringList list = selectedModel->stringList();
list.clear();
selectedModel->setStringList(list);
selectedModel->removeRows(0, selectedModel->rowCount());
updateHook();
} else
//ignore it otherwise

View File

@ -17,10 +17,14 @@
#include <QObject>
#include <QKeyEvent>
#include <QStringList>
#include <QStringListModel>
#include <QAbstractListModel>
#include <QListView>
#include <QPushButton>
#include "support/qstring_helpers.h"
#include <vector>
namespace lyx {
namespace frontend {
@ -45,8 +49,8 @@ public:
QPushButton * delPB,
QPushButton * upPB,
QPushButton * downPB,
QStringListModel * availableModel,
QStringListModel * selectedModel);
QAbstractListModel * availableModel,
QAbstractListModel * selectedModel);
/// 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.)
@ -82,6 +86,8 @@ protected:
///been selected (i.e., is also in selectedLV).
bool isSelected(const QModelIndex & idx);
///
bool insertRowToSelected(int i, QMap<int, QVariant> const & itemData);
///
QListView * availableLV;
///
QListView * selectedLV;
@ -94,9 +100,9 @@ protected:
///
QPushButton * downPB;
///
QStringListModel * availableModel;
QAbstractListModel * availableModel;
///
QStringListModel * selectedModel;
QAbstractListModel * selectedModel;
protected Q_SLOTS:
///
@ -104,13 +110,13 @@ protected Q_SLOTS:
///
void selectedChanged(const QModelIndex & idx, const QModelIndex &);
///
void addPB_clicked();
virtual void addPB_clicked();
///
void deletePB_clicked();
virtual void deletePB_clicked();
///
void upPB_clicked();
virtual void upPB_clicked();
///
void downPB_clicked();
virtual void downPB_clicked();
///
void availableLV_clicked(const QModelIndex &);
///
@ -129,7 +135,7 @@ private:
virtual void updateDownPB();
///
virtual void updateUpPB();
///
bool selectedHasFocus_;
};

View File

@ -86,6 +86,7 @@ SOURCEFILES = \
GuiFontMetrics.cpp \
GuiGraphics.cpp \
GuiHyperlink.cpp \
GuiIdListModel.cpp \
GuiImage.cpp \
GuiInclude.cpp \
GuiIndex.cpp \
@ -175,6 +176,7 @@ MOCHEADER = \
GuiFontExample.h \
GuiGraphics.h \
GuiHyperlink.h \
GuiIdListModel.h \
GuiInclude.h \
GuiIndex.h \
GuiKeySymbol.h \