Some time ago we had a discussion about what changes to layout files are
allowed in a stable release. There were several proposals, from simple but
limited to powerful but complicated. Meanwhile I had another idea which is
IMHO quite simple but still powerful: Introduce a new "force local" flag for
layouts. If this flag is set, the layout is always stored as a special local
layout in the .lyx file. This flag would be set for any style which is added
to LyX 2.1.x (with x > 0). Then any such document could always be used by
LyX 2.1.x-1 as well, even including export. The same style in 2.2 (or
whathever it will be called) would not use this flag. Therefore, the stored
local layouts would be automatically deleted once the document is saved by
2.2.
Attached is an untested sketch of the idea. The only missing part is
Layout::write(). Implementing this will be some work (which could be reused
for a layout editor btw), and therefore I'll only do it if this will go in.
What do you think?
Georg
diff --git a/lib/lyx2lyx/lyx_2_1.py b/lib/lyx2lyx/lyx_2_1.py
index ccb17eb..fe7f334 100644
--- a/lib/lyx2lyx/lyx_2_1.py
+++ b/lib/lyx2lyx/lyx_2_1.py
@@ -3672,6 +3672,34 @@ def revert_new_libertines(document):
document.header[k] = "\\font_sans default"
+def revert_forced_local_layout(document):
+ i = 0
+ while True:
+ i = find_token(document.header, "\\begin_forced_local_layout", i)
+ if i == -1:
+ return
+ j = find_end_of(document.header, i, "\\begin_forced_local_layout", "\\end_forced_local_layout")
+ if j == -1:
+ # this should not happen
+ break
+ k = find_token(document.header, "\\begin_local_layout", 0)
+ if k == -1:
+ document.header[i] = "\\begin_local_layout"
+ document.header[j] = "\\end_local_layout"
+ else:
+ l = find_end_of(document.header, k, "\\begin_local_layout", "\\end_local_layout")
+ if j == -1:
+ # this should not happen
+ break
+ lines = document.header[i+1 : j]
+ if k > i:
+ document.header[k+1 : k+1] = lines
+ document.header[i : j ] = []
+ else:
+ document.header[i : j ] = []
+ document.header[k+1 : k+1] = lines
+
+
##
# Conversion hub
#
@@ -3729,9 +3757,11 @@ convert = [
[462, []],
[463, [convert_encodings]],
[464, [convert_use_cancel]],
+ [465, []],
]
revert = [
+ [464, [revert_forced_local_layout]],
[463, [revert_use_cancel]],
[462, [revert_encodings]],
[461, [revert_new_libertines]],
diff --git a/lib/scripts/layout2layout.py b/lib/scripts/layout2layout.py
index 01737e0..52c83d3 100644
--- a/lib/scripts/layout2layout.py
+++ b/lib/scripts/layout2layout.py
@@ -154,6 +154,9 @@ import os, re, string, sys
# Incremented to format 45, 12 February 2013 by rgh
# New Tag "NoInsetLayout"
+# Incremented to format 46, 15 March 2013 by gb
+# New Tag "ForceLocal"
+
# Do not forget to document format change in Customization
# Manual (section "Declaring a new text class").
@@ -161,7 +164,7 @@ import os, re, string, sys
# development/tools/updatelayouts.sh script to update all
# layout files to the new format.
-currentFormat = 45
+currentFormat = 46
def usage(prog_name):
@@ -378,7 +381,7 @@ def convert(lines):
i += 1
continue
- if format == 44:
+ if format == 44 or format == 45:
# nothing to do.
i += 1
continue
diff --git a/src/Buffer.cpp b/src/Buffer.cpp
index b621365..beba5a1 100644
--- a/src/Buffer.cpp
+++ b/src/Buffer.cpp
@@ -831,7 +831,8 @@ int Buffer::readHeader(Lexer & lex)
params().html_latex_end.clear();
params().html_math_img_scale = 1.0;
params().output_sync_macro.erase();
- params().local_layout.clear();
+ params().setLocalLayout(string(), false);
+ params().setLocalLayout(string(), true);
for (int i = 0; i < 4; ++i) {
params().user_defined_bullet(i) = ITEMIZE_DEFAULTS[i];
diff --git a/src/BufferParams.cpp b/src/BufferParams.cpp
index b5aafa8..2b95d9e 100644
--- a/src/BufferParams.cpp
+++ b/src/BufferParams.cpp
@@ -627,7 +627,9 @@ string BufferParams::readToken(Lexer & lex, string const & token,
} else if (token == "\\begin_preamble") {
readPreamble(lex);
} else if (token == "\\begin_local_layout") {
- readLocalLayout(lex);
+ readLocalLayout(lex, false);
+ } else if (token == "\\begin_forced_local_layout") {
+ readLocalLayout(lex, true);
} else if (token == "\\begin_modules") {
readModules(lex);
} else if (token == "\\begin_removed_modules") {
@@ -990,6 +992,7 @@ void BufferParams::writeFile(ostream & os) const
<< convert<string>(maintain_unincluded_children) << '\n';
// local layout information
+ string const local_layout = getLocalLayout(false);
if (!local_layout.empty()) {
// remove '\n' from the end
string const tmplocal = rtrim(local_layout, "\n");
@@ -997,6 +1000,14 @@ void BufferParams::writeFile(ostream & os) const
<< tmplocal
<< "\n\\end_local_layout\n";
}
+ string const forced_local_layout = getLocalLayout(true);
+ if (!forced_local_layout.empty()) {
+ // remove '\n' from the end
+ string const tmplocal = rtrim(forced_local_layout, "\n");
+ os << "\\begin_forced_local_layout\n"
+ << tmplocal
+ << "\n\\end_forced_local_layout\n";
+ }
// then the text parameters
if (language != ignore_language)
@@ -2099,13 +2110,15 @@ void BufferParams::makeDocumentClass()
doc_class_ = getDocumentClass(*baseClass(), mods);
- if (!local_layout.empty()) {
- TextClass::ReturnValues success =
- doc_class_->read(local_layout, TextClass::MODULE);
- if (success != TextClass::OK && success != TextClass::OK_OLDFORMAT) {
- docstring const msg = _("Error reading internal layout information");
- frontend::Alert::warning(_("Read Error"), msg);
- }
+ TextClass::ReturnValues success = TextClass::OK;
+ if (!forced_local_layout_.empty())
+ success = doc_class_->read(forced_local_layout_, TextClass::MODULE);
+ if (!local_layout_.empty() &&
+ (success == TextClass::OK || success == TextClass::OK_OLDFORMAT))
+ success = doc_class_->read(local_layout_, TextClass::MODULE);
+ if (success != TextClass::OK && success != TextClass::OK_OLDFORMAT) {
+ docstring const msg = _("Error reading internal layout information");
+ frontend::Alert::warning(_("Read Error"), msg);
}
}
@@ -2122,6 +2135,24 @@ bool BufferParams::citationModuleCanBeAdded(string const & modName) const
}
+std::string BufferParams::getLocalLayout(bool forced) const
+{
+ if (forced)
+ return doc_class_->forcedLayouts();
+ else
+ return local_layout_;
+}
+
+
+void BufferParams::setLocalLayout(string const & layout, bool forced)
+{
+ if (forced)
+ forced_local_layout_ = layout;
+ else
+ local_layout_ = layout;
+}
+
+
bool BufferParams::addLayoutModule(string const & modName)
{
LayoutModuleList::const_iterator it = layout_modules_.begin();
@@ -2347,13 +2378,19 @@ void BufferParams::readPreamble(Lexer & lex)
}
-void BufferParams::readLocalLayout(Lexer & lex)
+void BufferParams::readLocalLayout(Lexer & lex, bool forced)
{
- if (lex.getString() != "\\begin_local_layout")
+ string const expected = forced ? "\\begin_forced_local_layout" :
+ "\\begin_local_layout";
+ if (lex.getString() != expected)
lyxerr << "Error (BufferParams::readLocalLayout):"
"consistency check failed." << endl;
- local_layout = lex.getLongString("\\end_local_layout");
+ if (forced)
+ forced_local_layout_ =
+ lex.getLongString("\\end_forced_local_layout");
+ else
+ local_layout_ = lex.getLongString("\\end_local_layout");
}
diff --git a/src/BufferParams.h b/src/BufferParams.h
index 2a669d0..9c558a6 100644
--- a/src/BufferParams.h
+++ b/src/BufferParams.h
@@ -162,6 +162,10 @@ public:
void clearLayoutModules() { layout_modules_.clear(); }
/// Clear the removed module list
void clearRemovedModules() { removed_modules_.clear(); }
+ /// Get the local layouts
+ std::string getLocalLayout(bool) const;
+ /// Set the local layouts
+ void setLocalLayout(std::string const &, bool);
/// returns \c true if the buffer contains a LaTeX document
bool isLatex() const;
@@ -305,8 +309,6 @@ public:
///
std::string preamble;
///
- std::string local_layout;
- ///
std::string options;
/// use the class options defined in the layout?
bool use_default_options;
@@ -483,7 +485,7 @@ private:
///
void readPreamble(Lexer &);
///
- void readLocalLayout(Lexer &);
+ void readLocalLayout(Lexer &, bool);
///
void readLanguage(Lexer &);
///
@@ -513,6 +515,10 @@ private:
/// this is for modules that are required by the document class but that
/// the user has chosen not to use
std::list<std::string> removed_modules_;
+ /// The local layouts without the forced ones
+ std::string local_layout_;
+ /// Forced local layouts only for reading (use getLocalLayout() instead)
+ std::string forced_local_layout_;
/// the list of included children (for includeonly)
std::list<std::string> included_children_;
diff --git a/src/Layout.cpp b/src/Layout.cpp
index deec49f..1ff5d5d 100644
--- a/src/Layout.cpp
+++ b/src/Layout.cpp
@@ -104,6 +104,7 @@ enum LayoutTags {
LT_REFPREFIX,
LT_RESETARGS,
LT_RIGHTDELIM,
+ LT_FORCELOCAL,
LT_INTITLE // keep this last!
};
@@ -166,6 +167,7 @@ bool Layout::read(Lexer & lex, TextClass const & tclass)
{ "endlabelstring", LT_ENDLABELSTRING },
{ "endlabeltype", LT_ENDLABELTYPE },
{ "font", LT_FONT },
+ { "forcelocal", LT_FORCELOCAL },
{ "freespacing", LT_FREE_SPACING },
{ "htmlattr", LT_HTMLATTR },
{ "htmlforcecss", LT_HTMLFORCECSS },
@@ -582,6 +584,10 @@ bool Layout::read(Lexer & lex, TextClass const & tclass)
case LT_SPELLCHECK:
lex >> spellcheck;
break;
+
+ case LT_FORCELOCAL:
+ lex >> forcelocal;
+ break;
}
}
lex.popTable();
@@ -958,6 +964,12 @@ void Layout::readArgument(Lexer & lex)
}
+bool Layout::write(ostream & os) const
+{
+ return false;
+}
+
+
Layout::LaTeXArgMap Layout::args() const
{
LaTeXArgMap args = latexargs_;
diff --git a/src/Layout.h b/src/Layout.h
index 88cb9a4..2ab1444 100644
--- a/src/Layout.h
+++ b/src/Layout.h
@@ -76,6 +76,8 @@ public:
///
void readArgument(Lexer &);
///
+ bool write(std::ostream &) const;
+ ///
docstring const & name() const { return name_; }
///
void setName(docstring const & n) { name_ = n; }
@@ -310,6 +312,8 @@ public:
/// Is this spellchecked?
bool spellcheck;
+ /// Should this layout definition always be written to the document preamble?
+ bool forcelocal;
private:
diff --git a/src/TextClass.cpp b/src/TextClass.cpp
index c48b68e..f4d894b 100644
--- a/src/TextClass.cpp
+++ b/src/TextClass.cpp
@@ -60,7 +60,7 @@ namespace lyx {
// development/tools/updatelayouts.sh script, to update the format of
// all of our layout files.
//
-int const LAYOUT_FORMAT = 45; // rgh: New Tag "NoInsetLayout"
+int const LAYOUT_FORMAT = 46; // gb: New Tag "ForceLocal"
namespace {
@@ -1371,6 +1371,17 @@ bool DocumentClass::addLayoutIfNeeded(docstring const & n) const
}
+string DocumentClass::forcedLayouts() const
+{
+ ostringstream os;
+ const_iterator const e = end();
+ for (const_iterator i = begin(); i != e; ++i)
+ if (i->forcelocal)
+ i->write(os);
+ return os.str();
+}
+
+
InsetLayout const & DocumentClass::insetLayout(docstring const & name) const
{
// FIXME The fix for the InsetLayout part of 4812 would be here:
diff --git a/src/TextClass.h b/src/TextClass.h
index bc900fa..9625c3e 100644
--- a/src/TextClass.h
+++ b/src/TextClass.h
@@ -399,6 +399,8 @@ public:
/// add a new layout \c name if it does not exist in layoutlist_
/// \return whether we had to add one.
bool addLayoutIfNeeded(docstring const & name) const;
+ /// Forced layouts in layout file syntax
+ std::string forcedLayouts() const;
///////////////////////////////////////////////////////////////////
// accessors
diff --git a/src/frontends/qt4/GuiDocument.cpp b/src/frontends/qt4/GuiDocument.cpp
index 6f6b4b9..5a9fbb0 100644
--- a/src/frontends/qt4/GuiDocument.cpp
+++ b/src/frontends/qt4/GuiDocument.cpp
@@ -517,7 +517,7 @@ LocalLayout::LocalLayout() : current_id_(0), validated_(false)
void LocalLayout::update(BufferParams const & params, BufferId id)
{
- QString layout = toqstr(params.local_layout);
+ QString layout = toqstr(params.getLocalLayout(false));
// Nothing to do if the params and preamble are unchanged.
if (id == current_id_
&& layout == locallayoutTE->document()->toPlainText())
@@ -533,7 +533,7 @@ void LocalLayout::update(BufferParams const & params, BufferId id)
void LocalLayout::apply(BufferParams & params)
{
string const layout = fromqstr(locallayoutTE->document()->toPlainText());
- params.local_layout = layout;
+ params.setLocalLayout(layout, false);
}
diff --git a/src/version.h b/src/version.h
index 94e5244..b831b1e 100644
--- a/src/version.h
+++ b/src/version.h
@@ -30,8 +30,8 @@ extern char const * const lyx_version_info;
// Do not remove the comment below, so we get merge conflict in
// independent branches. Instead add your own.
-#define LYX_FORMAT_LYX 464 // kornel: use_package cancel
-#define LYX_FORMAT_TEX2LYX 464 // kornel: use_package cancel
+#define LYX_FORMAT_LYX 465 // gb: new tag begin_forced_local_layout/end_forced_local_layout
+#define LYX_FORMAT_TEX2LYX 465 // gb: new tag begin_forced_local_layout/end_forced_local_layout
#if LYX_FORMAT_TEX2LYX != LYX_FORMAT_LYX
#ifndef _MSC_VER