On Tuesday 02 July 2002 12:25 pm, Andre Poenitz wrote:
> On Tue, Jul 02, 2002 at 01:13:26PM +0200, David Kastrup wrote:
> > Well, if you have any mechanisms for xdviing/ghostviewing just part of
> > a document, "local" defines will fail anyway if not included in such
> > a region.  I would class operation of previews similarly: defs
> > relevant to a preview should be placed either in the preamble, or
> > inside of the previewed material itself.
> >
> > Catering for more is being too clever, I think.  Let the user suffer
> > the consequences.
>
> I think it should get possible to get closer to the proper settings some
> day. Currently just using the preamble is probably the best trade-off
> between correctness and required work.

Indeed. 

Attached is a prototype PreviewQueue class. Currently it does no more than 
compile, but I believe it's fairly complete.

Note that I iterate over all MATHMACROs when I dump the preamble so we'll get 
previews of "reasonable" math insets.

I think that Buffer would have a 
        boost::scoped_ptr<grfx::PreviewQueue> previewer_;
member and that it would be passed lots of LaTeX snippets when the document 
was loaded. The code below will start off the conversion process, but we 
probably need a new Inset method to invoke grfx::PreviewQueue::addSnippet and 
connect to grfx::PreviewQueue::readyToLoad.

Anyway, you get the idea.
Feel free to comment.

Angus

void Buffer::initiatePreview() const
{
        // Loop over the insets and pass those of type MATH_CODE to 
        // the PreviewQueue
        Buffer::inset_iterator it = buffer_.inset_const_iterator_begin();
        Buffer::inset_iterator end = buffer_.inset_const_iterator_end();

        for (; it != end; ++it) {
                if ((*it)->lyxCode() == Inset::MATH_CODE) {
                        ostringstream os;
                        (*it)->latex(*this, os, true, true);
                        previewer_->addSnippet(os.str().c_str());
                }
        }

        previewer_.startProcessing();
}
// -*- C++ -*-
/**
 *  \file GraphicsPreview.h
 *  Copyright 2002 the LyX Team
 *  Read the file COPYING
 *
 * \author Angus Leeming <[EMAIL PROTECTED]>
 *
 *  grfx::PreviewQueue collects latex snippets together. Then, on a
 *  startProcessing() call, these are dumped to file and processed, converting
 *  each snippet to a separate bitmap image file. Once a bitmap file is ready
 *  to be loaded back into LyX, the PreviewQueue emits a readyToLoad signal
 *  to inform the initiating process.
 */

#ifndef GRAPHICSPREVIEW_H
#define GRAPHICSPREVIEW_H

#ifdef __GNUG__
#pragma interface
#endif

#include "LString.h"
#include <boost/utility.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/signals/signal2.hpp>

class Buffer;

namespace grfx {

class PreviewQueue : boost::noncopyable {
public:
	/** We pass a Buffer copy & so that we can dump the preamble to the
	 *  LaTeX file.
	 */
	PreviewQueue(Buffer const &);
	///
	~PreviewQueue();

	/// Add a snippet of LaTeX to the queue for processing.
	void addSnippet(string const & latex_snippet);

	/** We have accumulated several latex snippets.
	 *  Initiate the transformation into bitmap image files.
	 */
	void startProcessing();

	/** Emit this signal when the image file is ready to load.
	 *  Passes the LaTeX snippet and the name of the associated
	 *  bitmap image file to load that is now ready.
	 */
	boost::signal2<void, string const &, string const &> readyToLoad;

private:
	/// Use the Pimpl idiom to hide the internals.
	class Impl;
	/// The pointer never changes although *pimpl_'s contents may.
	boost::scoped_ptr<Impl> const pimpl_;
};

} // namespace grfx

#endif // GRAPHICSPREVIEW_H
/*
 *  \file GraphicsPreview.C
 *  Copyright 2002 the LyX Team
 *  Read the file COPYING
 *
 * \author Angus Leeming <[EMAIL PROTECTED]>
 */
#include <config.h>

#ifdef __GNUG__
#pragma implementation
#endif

#include "GraphicsPreview.h"

#include "buffer.h"
#include "bufferparams.h"
#include "debug.h"
#include "lyxrc.h"
#include "LColor.h"

#include "LaTeXFeatures.h" // temporary (buffer should do this).

#include "insets/inset.h"

#include "support/filetools.h"
#include "support/forkedcall.h"
#include "support/lstrings.h"
#include "support/lyxlib.h"

#include "Lsstream.h"        // temporary (hexname)
#include <X11/X.h>           // temporary (hexname)
#include FORMS_H_LOCATION    // temporary (hexname)

#include <boost/bind.hpp>
#include <boost/signals/trackable.hpp>

#include <fstream>
#include <iomanip>
#include <map>

using std::endl;
using std::ofstream;
using std::ostream;
using std::setbase;
using std::setfill;
using std::setw;


namespace {

string const unique_filename()
{
	static string const dir = OnlyPath(lyx::tempName());
	static int theCounter = 0;
	ostringstream os;
	os << dir << theCounter++ << "lyxpreview";

	return os.str().c_str();
}


// These are hard-coded for now.
// Replace eventually with a lyxrc variable.
string const preview_script("~/.lyx-1.3.0cvs/scripts/lyxpreview2ppm.sh");
string const final_format("ppm");

// This should go into lyx_gui
string const hexname(LColor::color const & col)
{
	string const name = lcolor.getX11Name(col);
	Display * display = fl_get_display();;
	Colormap const colormap = fl_state[fl_get_vclass()].colormap;
	XColor xcol, ccol;

	if (XLookupColor(display, colormap, name.c_str(), &xcol, &ccol) == 0) {
			lyxerr << "X can't find color \""
			       << lcolor.getLyXName(col)
			       << endl;
			return string();
	}

	ostringstream os;

	// Note that X stores the RGB values in the range 0 - 65535
	// whilst we require them in the range 0 - 255.
	os << setbase(16) << setfill('0')
	   << setw(2) << (xcol.red   / 256)
	   << setw(2) << (xcol.green / 256)
	   << setw(2) << (xcol.blue  / 256);

	return os.str().c_str();
}

} // namespace anon


namespace grfx {

struct PreviewQueue::Impl : public boost::signals::trackable {
	///
	Impl(PreviewQueue & p, Buffer const & b);
	///
	void addSnippet(string const & latex_snippet);
	///
	void startProcessing();
	/// Invoked by Forkedcall on finish
	void finishedProcessing(string const &, pid_t, int);

private:
	///
	ostream & dumpPreamble(ostream &) const;
	///
	ostream & dumpData(ostream &) const;

	/** The map stores the LaTeX snippet and the name of the generated
	 *  bitmap image file.
	 *  Allows repeated snippets to be caught and discarded before the
	 *  LaTeX file is dumped and processing begins.
	 */
	typedef std::map<string, string> DataType;
	///
	DataType data;
	///
	string filename_base_;
	///
	PreviewQueue & parent_;
	///
	Buffer const & buffer_;
};


PreviewQueue::PreviewQueue(Buffer const & b)
	: pimpl_(new Impl(*this, b))
{}


PreviewQueue::~PreviewQueue()
{}


void PreviewQueue::addSnippet(string const & latex_snippet)
{
	pimpl_->addSnippet(latex_snippet);
}


void PreviewQueue::startProcessing()
{
	pimpl_->startProcessing();
}


PreviewQueue::Impl::Impl(PreviewQueue & p, Buffer const & b)
	: filename_base_(unique_filename()), parent_(p), buffer_(b)
{}


void PreviewQueue::Impl::addSnippet(string const & latex_snippet)
{
	DataType::const_iterator it = data.find(latex_snippet);
	if (it != data.end())
		return;

	static int theCounter = 1;
	ostringstream os;
	os << filename_base_
	   << std::setfill('0') << setw(3) << theCounter++
	   << "." << final_format;
	string const image_filename = os.str().c_str();

	data[latex_snippet] = image_filename;
}


void PreviewQueue::Impl::startProcessing()
{
	string const latexfile = filename_base_ + ".tex";

	// Output the LaTeX file.
	ofstream of(latexfile.c_str());
	of << "\\batchmode"
	   << dumpPreamble(of)
	   << "\\begin{document}"
	   << dumpData(of)
	   << "\\end{document}\n";
	of.close();

	// Clear the data so we're ready to start again
	data.clear();

	// The conversion command.
	ostringstream cs;
	cs << "sh " << preview_script << " " << latexfile << " "
	   << tostr(lyxrc.dpi * lyxrc.zoom);
	
	string const command = cs.str().c_str();

	// Initiate the conversion
	Forkedcall::SignalTypePtr convert_ptr;
	convert_ptr.reset(new Forkedcall::SignalType);

	convert_ptr->connect(
		boost::bind(&Impl::finishedProcessing, this, _1, _2, _3));

	Forkedcall call;
	call.startscript(command, convert_ptr);

	// Reset the filename
	filename_base_ = unique_filename();
}


void PreviewQueue::Impl::finishedProcessing(string const & /* cmd */,
					    pid_t /* pid */, int retval)
{
	if (retval > 0)
		return;

	DataType::const_iterator it  = data.begin();
	DataType::const_iterator end = data.end();

	for (; it != end; ++it) {
		parent_.readyToLoad(it->first, it->second);
	}
}


ostream & PreviewQueue::Impl::dumpPreamble(ostream & os) const
{
	LaTeXFeatures features(buffer_.params);

	string tmp = features.getPackages();
	if (!tmp.empty())
		os << tmp << '\n';

	tmp = features.getMacros();
	if (!tmp.empty())
		os << tmp << '\n';

	tmp = features.getTClassPreamble();
	if (!tmp.empty())
		os << tmp << '\n';

	tmp = buffer_.params.preamble;
	if (!tmp.empty())
		os << tmp << '\n';

	// Loop over the insets in the buffer and insert all the math-macros
	Buffer::inset_iterator it = buffer_.inset_const_iterator_begin();
	Buffer::inset_iterator end = buffer_.inset_const_iterator_end();

	for (; it != end; ++it) {
		if ((*it)->lyxCode() == Inset::MATHMACRO_CODE) {
			(*it)->latex(&buffer_, os, true, true);
		}
	}

	// Use the preview style file to ensure that each snippet appears on a
	// fresh page
	os << "\\usepackage[active,dvips,tightpage]{preview}\n\n";

	// This piece of PostScript magic ensures that the foreground and
	// background colors are the same as the LyX screen.
	string fg = hexname(LColor::foreground);
	if (fg.empty()) fg = "000000";

	string bg = hexname(LColor::background);
	if (bg.empty()) bg = "ffffff";
	
	os << "\\AtBeginDocument{\\AtBeginDvi{%\n"
	   << "\\special{!userdict begin/bop-hook{//bop-hook exec\n"
	   << "<" << fg << bg << ">{255 div}forall setrgbcolor\n"
	   << "clippath fill setrgbcolor}bind def end}}}\n";

	return os;
}


ostream & PreviewQueue::Impl::dumpData(ostream & os) const
{
	DataType::const_iterator it  = data.begin();
	DataType::const_iterator end = data.end();

	for (; it != end; ++it) {
		os << "\\begin{preview}\n"
		   << it->first << '\n'
		   << "\\end{preview}\n";
	}

	return os;
}

} // namespace grfx

Reply via email to