Il 13/09/2011 14:43, Richard Heck ha scritto:
I guess I'd prefer to a separate LFUN_BUFFER_EXPORT_TO routine here, rather than this sort of trick with the arguments. There might one day be other differences one wants. I think that would also make it easier later to add the possibility to the frontend of choosing an export folder via a dialog.
[...]
And here, I guess I'd prefer a function that took the format and destination as arguments, where the latter might be empty. Then doExport can be called one way from LFUN_BUFFER_EXPORT and a different way (with the destination) from LFUN_BUFFER_EXPORT_AS.

Please, find attached the patch adapted along this line. As you can see, there is still a Buffer::doExportTo() that takes this "format /path/to/dest" target specification, which should be changed to an additional argument. However, I don't know how to change the according code in GuiView.cpp (asyncBufferProcessing & friends).

I'd appreciate if anyone could instruct me on how to do an asyncBufferProcessing() call

            d.asyncBufferProcessing(argument,
                        doc_buffer,
                        _("Exporting ..."),
&GuiViewPrivate::exportAndDestroyTo,
&Buffer::doExportTo,
                        0);

in which the prototype of Buffer::doExportTo() is slightly changed with one additional parameter, that will be obtained by parsing the "argument" variable that you can see in the call above.

IMHO, as compared to my previous patch, here there's a fair amount of unneeded replication of code, but that may be a matter of taste.

Also, even though I couldn't get perfectly how this works yet, another weird thing that seems really strange to me, is why do we replicate twice the method name to be called asynchronously. For example, in addition to the above, the ::doExportTo() is also mentioned in the ::exportAndDestroyTo() method:

docstring GuiView::GuiViewPrivate::exportAndDestroyTo(Buffer const * orig, Buffer * buffer, string const & format)
{
bool (Buffer::* mem_func)(std::string const &, bool, bool) const = &Buffer::doExportTo; return runAndDestroy(bind(mem_func, buffer, _1, false, _2), orig, buffer, format, "export");
}

So, why do we provide the pointer to Buffer::doExportTo() twice ?

This was merely copied from how asyncBufferProcessing() was called for Buffer::doExport().

Thanks,

    T.

Index: src/LyXAction.cpp
===================================================================
--- src/LyXAction.cpp	(revisione 39673)
+++ src/LyXAction.cpp	(copia locale)
@@ -3514,6 +3514,25 @@
  */
 		{ LFUN_INSET_COPY_AS, "inset-copy-as", ReadOnly | NoUpdate | AtPoint, Edit },
 
+/*!
+ * \var lyx::FuncCode lyx::LFUN_BUFFER_EXPORT_TO
+ * \li Action: Exports the current buffer (document) to the given format and destination.
+ * \li Syntax: buffer-export <FORMAT> <DEST>
+ * \li Params: <FORMAT> is either "custom" or one of the formats which you
+                        can find in Tools->Preferences->File formats->Format.
+                        Usual format you will enter is "pdf2" (pdflatex),
+                        "pdflatex" (plain tex for pdflatex) or "ps" for postscript.\n
+                        In case of "custom" you will be asked for a format you
+                        want to start from and for the command that you want to
+                        apply to this format. Internally the control is then passed
+                        to #LFUN_BUFFER_EXPORT_CUSTOM.
+ * \li Params: <DEST> is the destination file-name for the export operation. It also
+                      sets the export folder to the one containing the specified file-name.
+ * \li Origin: tommaso, 14 Sep 2011
+ * \endvar
+ */
+		{ LFUN_BUFFER_EXPORT_TO, "buffer-export-to", ReadOnly, Buffer },
+
 		{ LFUN_NOACTION, "", Noop, Hidden }
 #ifndef DOXYGEN_SHOULD_SKIP_THIS
 	};
Index: src/insets/InsetGraphics.cpp
===================================================================
--- src/insets/InsetGraphics.cpp	(revisione 39673)
+++ src/insets/InsetGraphics.cpp	(copia locale)
@@ -789,7 +789,14 @@
 	// Convert the file if necessary.
 	// Remove the extension so LaTeX will use whatever is appropriate
 	// (when there are several versions in different formats)
-	latex_str += prepareFile(runparams);
+	string file_path = prepareFile(runparams);
+	if (!runparams.export_folder.empty()) {
+		/// Relative pathnames starting with ../ will be sanitized
+		/// if exporting to a different folder
+		while (file_path.substr(0, 17) == "\\lyxdot \\lyxdot /")
+			file_path = file_path.substr(17, file_path.length() - 17);
+	}
+	latex_str += file_path;
 	latex_str += '}' + after;
 	// FIXME UNICODE
 	os << from_utf8(latex_str);
Index: src/insets/InsetInclude.cpp
===================================================================
--- src/insets/InsetInclude.cpp	(revisione 39673)
+++ src/insets/InsetInclude.cpp	(copia locale)
@@ -513,15 +513,20 @@
 					      from_utf8(masterBuffer->filePath())));
 	}
 
+	string exppath = incfile;
+	if (!runparams.export_folder.empty())
+		exppath = makeAbsPath(exppath, runparams.export_folder).realPath();
+	FileName(exppath).onlyPath().createPath();
+
 	// write it to a file (so far the complete file)
 	string exportfile;
 	string mangled;
 	// bug 5681
 	if (type(params()) == LISTINGS) {
-		exportfile = incfile;
+		exportfile = exppath;
 		mangled = DocFileName(included_file).mangledFileName();
 	} else {
-		exportfile = changeExtension(incfile, ".tex");
+		exportfile = changeExtension(exppath, ".tex");
 		mangled = DocFileName(changeExtension(included_file.absFileName(), ".tex")).
 			mangledFileName();
 	}
@@ -702,6 +707,8 @@
 		break;
 	} 
 	case LISTINGS: {
+		runparams.exportdata->addExternalFile(tex_format, writefile,
+						      exportfile);
 		os << '\\' << from_ascii(params().getCmdName());
 		string const opt = to_utf8(params()["lstparams"]);
 		// opt is set in QInclude dialog and should have passed validation.
@@ -832,8 +839,13 @@
 		return 0;
 	}
 
+	string exppath = incfile;
+	if (!runparams.export_folder.empty())
+		exppath = makeAbsPath(exppath, runparams.export_folder).realPath();
+	FileName(exppath).onlyPath().createPath();
+
 	// write it to a file (so far the complete file)
-	string const exportfile = changeExtension(incfile, ".sgml");
+	string const exportfile = changeExtension(exppath, ".sgml");
 	DocFileName writefile(changeExtension(included_file, ".sgml"));
 
 	Buffer * tmp = loadIfNeeded();
Index: src/LyX.cpp
===================================================================
--- src/LyX.cpp	(revisione 39673)
+++ src/LyX.cpp	(copia locale)
@@ -1054,6 +1054,9 @@
 		  "                  Look on Tools->Preferences->File formats->Format\n"
 		  "                  to get an idea which parameters should be passed.\n"
 		  "                  Note that the order of -e and -x switches matters.\n"
+		  "\t-E [--export-to] fmt filename\n"
+		  "                  where fmt is the export format of choice (see --export),\n"
+		  "                  and filename is the destination filename.\n"
 		  "\t-i [--import] fmt file.xxx\n"
 		  "                  where fmt is the import format of choice\n"
 		  "                  and file.xxx is the file to be imported.\n"
@@ -1123,6 +1126,24 @@
 }
 
 
+int parse_export_to(string const & type, string const & output_file, string & batch)
+{
+	if (type.empty()) {
+		lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
+					 "--export-to switch")) << endl;
+		exit(1);
+	}
+	if (output_file.empty()) {
+		lyxerr << to_utf8(_("Missing destination filename after "
+					 "--export-to switch")) << endl;
+		exit(1);
+	}
+	batch = "buffer-export-to " + type + " " + output_file;
+	use_gui = false;
+	return 2;
+}
+
+
 int parse_export(string const & type, string const &, string & batch)
 {
 	if (type.empty()) {
@@ -1218,6 +1239,8 @@
 	cmdmap["--execute"] = parse_execute;
 	cmdmap["-e"] = parse_export;
 	cmdmap["--export"] = parse_export;
+	cmdmap["-E"] = parse_export_to;
+	cmdmap["--export-to"] = parse_export_to;
 	cmdmap["-i"] = parse_import;
 	cmdmap["--import"] = parse_import;
 	cmdmap["-geometry"] = parse_geometry;
Index: src/Exporter.h
===================================================================
--- src/Exporter.h	(revisione 39673)
+++ src/Exporter.h	(copia locale)
@@ -30,7 +30,9 @@
 
 
 /** copy file \p sourceFile to \p destFile. If \p force is false, the user
- *  will be asked before existing files are overwritten.
+ *  will be asked before existing files are overwritten. If \p only_tmp is
+ *  true, then only copy files that are in our tmp dir (to avoid other files
+ *  to overwrite themselves).
  *  \return
  *  - SUCCESS if this file got copied
  *  - FORCE   if subsequent calls should not ask for confirmation before
@@ -39,7 +41,7 @@
  */
 CopyStatus copyFile(std::string const & format,
 	support::FileName const & sourceFile, support::FileName const & destFile,
-	std::string const & latexFile, bool force);
+	std::string const & latexFile, bool force, bool only_tmp = true);
 
 
 class ExportedFile {
Index: src/Buffer.h
===================================================================
--- src/Buffer.h	(revisione 39673)
+++ src/Buffer.h	(copia locale)
@@ -607,8 +607,18 @@
 		bool includeall, std::string & result_file) const;
 	///
 	bool doExport(std::string const & format, bool put_in_tempdir,
-		      bool includeall = false) const;
+		bool includeall = false) const;
 	///
+	bool doExportParams(std::string const & format, bool put_in_tempdir,
+		bool includeall, std::string filename,
+		OutputParams & runparams, std::string & result_file) const;
+	/// \p target is a format followed by an export filename
+	bool doExportTo(std::string const & target, bool put_in_tempdir,
+		bool includeall, std::string & result_file) const;
+	///
+	bool doExportTo(std::string const & format, bool put_in_tempdir,
+		bool includeall = false) const;
+	///
 	bool preview(std::string const & format, bool includeall = false) const;
 	/// mark the buffer as busy exporting something, or not
 	void setExportStatus(bool e) const;
Index: src/OutputParams.h
===================================================================
--- src/OutputParams.h	(revisione 39673)
+++ src/OutputParams.h	(copia locale)
@@ -251,6 +251,9 @@
 	
 	/// Include all children notwithstanding the use of \includeonly
 	bool includeall;
+
+	/// Explicit output folder, if any is desired
+	std::string export_folder;
 };
 
 
Index: src/frontends/qt4/GuiView.cpp
===================================================================
--- src/frontends/qt4/GuiView.cpp	(revisione 39673)
+++ src/frontends/qt4/GuiView.cpp	(copia locale)
@@ -393,6 +393,7 @@
 	static QSet<Buffer const *> busyBuffers;
 	static docstring previewAndDestroy(Buffer const * orig, Buffer * buffer, string const & format);
 	static docstring exportAndDestroy(Buffer const * orig, Buffer * buffer, string const & format);
+	static docstring exportAndDestroyTo(Buffer const * orig, Buffer * buffer, string const & format);
 	static docstring compileAndDestroy(Buffer const * orig, Buffer * buffer, string const & format);
 	static docstring autosaveAndDestroy(Buffer const * orig, Buffer * buffer);
 
@@ -2982,6 +2983,13 @@
 }
 
 
+docstring GuiView::GuiViewPrivate::exportAndDestroyTo(Buffer const * orig, Buffer * buffer, string const & format)
+{
+	bool (Buffer::* mem_func)(std::string const &, bool, bool) const = &Buffer::doExportTo;
+	return runAndDestroy(bind(mem_func, buffer, _1, false, _2), orig, buffer, format, "export");
+}
+
+
 docstring GuiView::GuiViewPrivate::previewAndDestroy(Buffer const * orig, Buffer * buffer, string const & format)
 {
 	bool(Buffer::* mem_func)(std::string const &, bool) const = &Buffer::preview;
@@ -3157,6 +3165,34 @@
 			break;
 		}
 
+		case LFUN_BUFFER_EXPORT_TO: {
+			if (!doc_buffer)
+				break;
+			// GCC only sees strfwd.h when building merged
+			if (::lyx::operator==(cmd.argument(), "custom")) {
+				dispatch(FuncRequest(LFUN_DIALOG_SHOW, "sendto"), dr);
+				break;
+			}
+#if QT_VERSION < 0x040400
+			if (!doc_buffer->doExportTo(argument, false)) {
+				dr.setError(true);
+				dr.setMessage(bformat(_("Error exporting to format: %1$s"),
+					cmd.argument()));
+			}
+#else
+			/* TODO/Review: Is it a problem to also export the children?
+					See the update_unincluded flag */
+			d.asyncBufferProcessing(argument,
+						doc_buffer,
+						_("Exporting ..."),
+						&GuiViewPrivate::exportAndDestroyTo,
+						&Buffer::doExportTo,
+						0);
+			// TODO Inform user about success
+#endif
+			break;
+		}
+
 		case LFUN_BUFFER_UPDATE: {
 			d.asyncBufferProcessing(argument,
 						doc_buffer,
Index: src/Exporter.cpp
===================================================================
--- src/Exporter.cpp	(revisione 39673)
+++ src/Exporter.cpp	(copia locale)
@@ -53,7 +53,9 @@
 
 
 /** copy file \p sourceFile to \p destFile. If \p force is false, the user
- *  will be asked before existing files are overwritten.
+ *  will be asked before existing files are overwritten. If \p only_tmp is
+ *  true, then only copy files that are in our tmp dir (to avoid other files
+ *  to overwrite themselves).
  *  \return
  *  - SUCCESS if this file got copied
  *  - FORCE   if subsequent calls should not ask for confirmation before
@@ -62,17 +64,16 @@
  */
 CopyStatus copyFile(string const & format,
 		    FileName const & sourceFile, FileName const & destFile,
-		    string const & latexFile, bool force)
+		    string const & latexFile, bool force, bool only_tmp)
 {
 	CopyStatus ret = force ? FORCE : SUCCESS;
 
-	// Only copy files that are in our tmp dir, all other files would
-	// overwrite themselves. This check could be changed to
+	// This check could be changed to
 	// boost::filesystem::equivalent(sourceFile, destFile) if export to
 	// other directories than the document directory is desired.
 	// Also don't overwrite files that already exist and are identical
 	// to the source files.
-	if (!prefixIs(onlyPath(sourceFile.absFileName()), package().temp_dir().absFileName())
+	if ((only_tmp && !prefixIs(onlyPath(sourceFile.absFileName()), package().temp_dir().absFileName()))
 	    || sourceFile.checksum() == destFile.checksum())
 		return ret;
 
Index: src/FuncCode.h
===================================================================
--- src/FuncCode.h	(revisione 39673)
+++ src/FuncCode.h	(copia locale)
@@ -449,6 +449,7 @@
 	LFUN_FORWARD_SEARCH,
 	LFUN_SCRIPT_INSERT,             // gb, 20101123
 	// 350
+	LFUN_BUFFER_EXPORT_TO,		// tommaso, 20110914
 
 	LFUN_LASTACTION                 // end of the table
 };
Index: src/Buffer.cpp
===================================================================
--- src/Buffer.cpp	(revisione 39673)
+++ src/Buffer.cpp	(copia locale)
@@ -1304,6 +1304,7 @@
 			   bool output_preamble, bool output_body) const
 {
 	OutputParams runparams = runparams_in;
+	fname.onlyPath().createPath();
 
 	// This is necessary for LuaTeX/XeTeX with tex fonts.
 	// See FIXME in BufferParams::encoding()
@@ -1935,6 +1936,23 @@
 			break;
 		}
 
+		case LFUN_BUFFER_EXPORT_TO: {
+			docstring const arg = cmd.argument();
+			if (arg == "custom") {
+				enable = true;
+				break;
+			}
+			string format = to_utf8(arg);
+			size_t pos = format.find(' ');
+			if (pos != string::npos)
+				format = format.substr(0, pos);
+			enable = params().isExportable(format);
+			if (!enable)
+				flag.message(bformat(
+					_("Don't know how to export to format: %1$s"), arg));
+			break;
+		}
+
 		case LFUN_BUFFER_CHKTEX:
 			enable = params().isLatex() && !lyxrc.chktex_command.empty();
 			break;
@@ -2008,6 +2026,15 @@
 		break;
 	}
 
+	case LFUN_BUFFER_EXPORT_TO: {
+		bool success = doExportTo(argument, false, false);
+		dr.setError(!success);
+		if (!success)
+			dr.setMessage(bformat(_("Error exporting to format: %1$s."), 
+					      func.argument()));
+		break;
+	}
+
 	case LFUN_BUILD_PROGRAM:
 		doExport("program", true, false);
 		break;
@@ -3391,12 +3418,35 @@
 }
 
 
+bool Buffer::doExportTo(string const & target, bool put_in_tempdir,
+	bool includeall, string & result_file) const
+{
+	OutputParams runparams(&params().encoding());
+	string format = target;
+	string filename;
+	size_t pos = target.find(' ');
+	if (pos != string::npos) {
+		filename = target.substr(pos + 1, target.length() - pos - 1);
+		format = target.substr(0, pos);
+		runparams.export_folder = FileName(filename).onlyPath().realPath();
+	}
+	return doExportParams(format, put_in_tempdir, includeall, filename, runparams, result_file);
+}
+
+
 bool Buffer::doExport(string const & format, bool put_in_tempdir,
 	bool includeall, string & result_file) const
 {
+	OutputParams runparams(&params().encoding());
+	return doExportParams(format, put_in_tempdir, includeall, string(), runparams, result_file);
+}
+
+
+bool Buffer::doExportParams(string const & format, bool put_in_tempdir,
+	bool includeall, string filename, OutputParams & runparams, string & result_file) const
+{
 	MarkAsExporting exporting(this);
 	string backend_format;
-	OutputParams runparams(&params().encoding());
 	runparams.flavor = OutputParams::LATEX;
 	runparams.linelen = lyxrc.plaintext_linelen;
 	runparams.includeall = includeall;
@@ -3439,10 +3489,12 @@
 			runparams.flavor = OutputParams::XETEX;
 	}
 
-	string filename = latexName(false);
-	filename = addName(temppath(), filename);
-	filename = changeExtension(filename,
-				   formats.extension(backend_format));
+	if (filename.empty()) {
+		filename = latexName(false);
+		filename = addName(temppath(), filename);
+		filename = changeExtension(filename,
+					   formats.extension(backend_format));
+	}
 
 	// Plain text backend
 	if (backend_format == "text") {
@@ -3557,7 +3609,8 @@
 	// if format == "dvi") to the result dir.
 	vector<ExportedFile> const files =
 		runparams.exportdata->externalFiles(format);
-	string const dest = onlyPath(result_file);
+	string const dest = runparams.export_folder.empty() ?
+		onlyPath(result_file) : runparams.export_folder;
 	bool use_force = use_gui ? lyxrc.export_overwrite == ALL_FILES
 				 : force_overwrite == ALL_FILES;
 	CopyStatus status = use_force ? FORCE : SUCCESS;
@@ -3566,9 +3619,15 @@
 	vector<ExportedFile>::const_iterator const en = files.end();
 	for (; it != en && status != CANCEL; ++it) {
 		string const fmt = formats.getFormatFromFile(it->sourceName);
+		string fixedName = it->exportName;
+		while (fixedName.substr(0, 3) == "../")
+			fixedName = fixedName.substr(3, fixedName.length() - 3);
+		FileName fixedFileName = makeAbsPath(fixedName, dest);
+		fixedFileName.onlyPath().createPath();
 		status = copyFile(fmt, it->sourceName,
-			makeAbsPath(it->exportName, dest),
-			it->exportName, status == FORCE);
+			fixedFileName,
+			it->exportName, status == FORCE,
+			runparams.export_folder.empty());
 	}
 
 	if (status == CANCEL) {
@@ -3608,6 +3667,18 @@
 }
 
 
+bool Buffer::doExportTo(string const & target, bool put_in_tempdir,
+		        bool includeall) const
+{
+	string result_file;
+	// (1) export with all included children (omit \includeonly)
+	if (includeall && !doExportTo(target, put_in_tempdir, true, result_file))
+		return false;
+	// (2) export with included children only
+	return doExportTo(target, put_in_tempdir, false, result_file);
+}
+
+
 bool Buffer::preview(string const & format, bool includeall) const
 {
 	MarkAsExporting exporting(this);

Reply via email to