The attached patch adds a facility for file-specific layout, e.g.:

\begin_local_layout
Format 6
InsetLayout CharStyle:MenuItem
LyxType               charstyle
LabelString           menu
LatexType             command
LatexName             menuitem
Font
Family              Sans
EndFont
Preamble
\newcommand{\menuitem}[1]{\sffamily{#1}}
EndPreamble
End
\end_local_layout

which I presently have working in the headers of Customization.lyx. As I've started to use 1.6 a bit, I've found that this kind of file-specific layout is incredibly useful. If I'm working on a file, and I want to define a new character style, or paragraph layout, or whatever, I may want it only for that file. I don't want to have to create a *.module and then copy it somewhere, etc, etc. I just want to create layout.

Comments?

At present, I'm proposing to commit the patch as-is, without UI, and then add UI later. (This should be simple enough.) It's very much an "advanced feature", so I'd like to discourage people from using it, actually, unless they REALLY know what they are doing. Any thoughts about that?

Ultimately, this could also help solve some of Bo's worries about bundling. In principle, one could embed an entire layout file the same way.

Richard

Index: src/BufferParams.h
===================================================================
--- src/BufferParams.h	(revision 23883)
+++ src/BufferParams.h	(working copy)
@@ -220,6 +220,8 @@
 	///
 	std::string preamble;
 	///
+	std::string local_layout;
+	///
 	std::string options;
 	///
 	std::string float_placement;
@@ -316,6 +318,8 @@
 	///
 	void readPreamble(Lexer &);
 	///
+	void readLocalLayout(Lexer &);
+	///
 	void readLanguage(Lexer &);
 	///
 	void readGraphicsDriver(Lexer &);
Index: src/BufferParams.cpp
===================================================================
--- src/BufferParams.cpp	(revision 23883)
+++ src/BufferParams.cpp	(working copy)
@@ -506,6 +506,8 @@
 		
 	} else if (token == "\\begin_preamble") {
 		readPreamble(lex);
+	} else if (token == "\\begin_local_layout") {
+		readLocalLayout(lex);
 	} else if (token == "\\begin_modules") {
 		readModules(lex);
 	} else if (token == "\\options") {
@@ -722,6 +724,15 @@
 		os << "\\end_modules" << '\n';
 	}
 
+	// local layout information
+	if (!local_layout.empty()) {
+		// remove '\n' from the end 
+		string const tmplocal = rtrim(local_layout, "\n");
+		os << "\\begin_local_layout\n"
+		   << tmplocal
+		   << "\n\\end_local_layout\n";
+	}
+
 	// then the text parameters
 	if (language != ignore_language)
 		os << "\\language " << language->lang() << '\n';
@@ -1501,6 +1512,12 @@
 			frontend::Alert::warning(_("Read Error"), msg);
 		}
 	}
+	if (!local_layout.empty()) {
+		if (!doc_class_->read(local_layout, TextClass::MODULE)) {
+			docstring const msg = _("Error reading internal layout information");
+			frontend::Alert::warning(_("Read Error"), msg);
+		}
+	}
 }
 
 
@@ -1555,6 +1572,16 @@
 }
 
 
+void BufferParams::readLocalLayout(Lexer & lex)
+{
+	if (lex.getString() != "\\begin_local_layout")
+		lyxerr << "Error (BufferParams::readLocalLayout):"
+			"consistency check failed." << endl;
+
+	local_layout = lex.getLongString("\\end_local_layout");
+}
+
+
 void BufferParams::readLanguage(Lexer & lex)
 {
 	if (!lex.next()) return;
Index: src/TextClass.h
===================================================================
--- src/TextClass.h	(revision 23883)
+++ src/TextClass.h	(working copy)
@@ -129,9 +129,20 @@
 		MERGE, //>This is a file included in a layout file
 		MODULE //>This is a layout module
 	};
+	/// return values for read()
+	enum ReturnValues {
+		OK,
+		ERROR,
+		FORMAT_MISMATCH
+	};
+
 	/// Performs the read of the layout file.
 	/// \return true on success.
 	bool read(support::FileName const & filename, ReadType rt = BASECLASS);
+	///
+	bool read(std::string const & str, ReadType rt = BASECLASS);
+	///
+	ReturnValues read(Lexer & lex, ReadType rt = BASECLASS);
 
 	///////////////////////////////////////////////////////////////////
 	// loading
@@ -242,6 +253,8 @@
 	///////////////////////////////////////////////////////////////////
 	///
 	bool deleteLayout(docstring const &);
+	///
+	bool convertLayoutFormat(support::FileName const &, ReadType);
 	/// \return true for success.
 	bool readStyle(Lexer &, Layout &);
 	///
Index: src/TextClass.cpp
===================================================================
--- src/TextClass.cpp	(revision 23883)
+++ src/TextClass.cpp	(working copy)
@@ -180,14 +180,7 @@
 };
 
 
-// Reads a textclass structure from file.
-bool TextClass::read(FileName const & filename, ReadType rt)
-{
-	if (!filename.isReadableFile()) {
-		lyxerr << "Cannot read layout file `" << filename << "'."
-		       << endl;
-		return false;
-	}
+namespace {
 
 	keyword_item textClassTags[] = {
 		{ "classoptions",    TC_CLASSOPTIONS },
@@ -216,14 +209,36 @@
 		{ "titlelatextype",  TC_TITLELATEXTYPE },
 		{ "tocdepth",        TC_TOCDEPTH }
 	};
+	
+} //namespace anon
 
+
+bool TextClass::convertLayoutFormat(support::FileName const & filename, ReadType rt)
+{
+	LYXERR(Debug::TCLASS, "Converting layout file to " << FORMAT);
+		FileName const tempfile = FileName::tempName();
+		bool success = layout2layout(filename, tempfile);
+		if (success)
+			read(tempfile, rt);
+		tempfile.removeFile();
+		return success;
+}
+
+bool TextClass::read(FileName const & filename, ReadType rt)
+{
+	if (!filename.isReadableFile()) {
+		lyxerr << "Cannot read layout file `" << filename << "'."
+		       << endl;
+		return false;
+	}
+
 	LYXERR(Debug::TCLASS, "Reading " + translateRT(rt) + ": " +
 		to_utf8(makeDisplayPath(filename.absFilename())));
 
 	// Define the `empty' layout used in table cells, ert, etc. Note that 
 	// we do this before loading any layout file, so that classes can 
 	// override features of this layout if they should choose to do so.
-	if (rt == BASECLASS) {
+	if (rt == BASECLASS && !hasLayout(emptylayout_)) {
 		static char const * s = "Margin Static\n"
 			"LatexType Paragraph\n"
 			"LatexName dummy\n"
@@ -243,11 +258,43 @@
 		};
 		layoutlist_.push_back(lay);
 	}
+	Lexer lexrc(textClassTags,
+		sizeof(textClassTags) / sizeof(textClassTags[0]));
 
+	lexrc.setFile(filename);
+	ReturnValues retval = read(lexrc, rt);
+	
+	LYXERR(Debug::TCLASS, "Finished reading " + translateRT(rt) + ": " +
+			to_utf8(makeDisplayPath(filename.absFilename())));
+	
+	if (retval != FORMAT_MISMATCH) 
+		return retval == OK;
+	
+	bool const worx = convertLayoutFormat(filename, rt);
+	if (!worx) {
+		lyxerr << "Unable to convert " << filename << 
+			" to format " << FORMAT << std::endl;
+		return false;
+	}
+	return true;
+}
+
+
+bool TextClass::read(std::string const & str, ReadType rt) 
+{
 	Lexer lexrc(textClassTags,
 		sizeof(textClassTags) / sizeof(textClassTags[0]));
+	istringstream is(str);
+	lexrc.setStream(is);
+	ReturnValues retval = read(lexrc, rt);
+	// FIXME We should deal with format errors here, too.
+	return retval == OK;
+}
 
-	lexrc.setFile(filename);
+
+// Reads a textclass structure from file.
+TextClass::ReturnValues TextClass::read(Lexer & lexrc, ReadType rt) 
+{
 	bool error = !lexrc.isOK();
 
 	// Format of files before the 'Format' tag was introduced
@@ -482,22 +529,11 @@
 			break;
 	}
 
-	if (format != FORMAT) {
-		LYXERR(Debug::TCLASS, "Converting layout file from format "
-				      << format << " to " << FORMAT);
-		FileName const tempfile = FileName::tempName();
-		bool success = layout2layout(filename, tempfile);
-		if (success)
-			 read(tempfile, rt);
-		tempfile.removeFile();
-		return success;
-	}
+	if (format != FORMAT)
+		return FORMAT_MISMATCH;
 
-	LYXERR(Debug::TCLASS, "Finished reading " + translateRT(rt) + ": " +
-			to_utf8(makeDisplayPath(filename.absFilename())));
-
 	if (rt != BASECLASS) 
-		return !error;
+		return (error ? ERROR : OK);
 
 	if (defaultlayout_.empty()) {
 		lyxerr << "Error: Textclass '" << name_
@@ -547,7 +583,7 @@
 	LYXERR(Debug::TCLASS, "Minimum TocLevel is " << min_toclevel_
 		<< ", maximum is " << max_toclevel_);
 
-	return !error;
+	return (error ? ERROR : OK);
 }
 
 

Reply via email to