It looks like I opened a can of worms with this XFig stuff :-(

Trivial as it may seem, it just isn't that easy to define and use a
$$orig_i placeholder. Lots of messy and fragile changes all over the
place.

However, it seems to me that the problems can be isolated to the concept of
'moving a file from one place to another'. I think that we need a class to
reflect this concept.

Usually, Mover will just invoke '::rename', or 'mv' when a shell script
representation is requested for the graphics converter. However, this will
be configurable, based on file format. Users can register an external
command to do something more complex. For example:

\mover "fig" "sh $$s/move_fig.sh $$i $$o"

See attached files mover.[Ch]. 

The advantage, of course, is that the approach is extendable to arbitrary
formats. Tgif and Dia spring to mind.

Does this seem like the right way to go?

-- 
Angus
/**
 * \file mover.C
 * This file is part of LyX, the document processor.
 * Licence details can be found in the file COPYING.
 *
 * \author Angus Leeming
 *
 * Full author contact details are available in file CREDITS.
 */

#include "mover.h"

#include "format.h"

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

#include <sstream>

using std::ostringstream;
using std::string;

namespace support = lyx::support;


bool Mover::move(string const & from, string const & to) const
{
	return support::rename(from, to);
}


string const
Mover::sh_move(string const & from, string const & to) const
{
	ostringstream out;
	out << "fromfile=" << from << "\n"
	    << "tofile="   << to << "\n\n"
	    << "'mv' -f \"${fromfile}\" \"${tofile}\" ||\n"
	    << "{\n"
	    << "\t'cp' -f \"${fromfile}\" \"${tofile}\" ||\n"
	    << "\t{\n"
	    << "\t\texit 1\n"
	    << "\t}\n"
	    << "\t'rm' -f \"${fromfile}\"\n"
	    << "}\n";

	return out.str();
}


SpecialisedMover::SpecialisedMover(string const & command)
	: command_(support::LibScriptSearch(command))
{}


bool SpecialisedMover::move(string const & from, string const & to) const
{
	string command = support::subst(command_, "$$i", from);
	command = support::subst(command, "$$o", to);

	support::Systemcall one;
	return one.startscript(support::Systemcall::Wait, command);
}


string const
SpecialisedMover::sh_move(string const & from, string const & to) const
{
	string command = support::subst(command_, "$$i", "\"${fromfile}\"");
	command = support::subst(command, "$$o", "\"${tofile}\"");

	return command + " || exit 1\n";
}


Movers & Movers::get()
{
	static Movers singleton;
	return singleton;
}


void Movers::set(Format const & fmt, string const & command)
{
	typedef boost::shared_ptr<SpecialisedMover> SpecialisedMoverPtr;

	specials_[fmt.name()] =
		SpecialisedMoverPtr(new SpecialisedMover(command));
}


Mover const & Movers::operator()(Format const & fmt) const
{
	SpecialsMap::const_iterator it = specials_.find(fmt.name());
	return (it == specials_.end()) ? default_ : *it->second;
}


// -*- C++ -*-
/**
 * \file mover.h
 * This file is part of LyX, the document processor.
 * Licence details can be found in the file COPYING.
 *
 * \author Angus Leeming
 *
 * Full author contact details are available in file CREDITS.
 */

#ifndef MOVER_H
#define MOVER_H

#include <boost/noncopyable.hpp>
#include <boost/shared_ptr.hpp>

#include <map>
#include <string>

class Format;

/**
 *  Utility to move a file of a specified format from one directory to
 *  another or to output a snippet of sh-script that will perform the
 *  move.
 *
 *  This base class simply invokes the system command ::rename() or
 *  outputs a sh-code snippet that uses 'mv' and 'cp'.
 */
class Mover {
public:
	virtual ~Mover() {}

	/** Move file @c from to @c to.
	 *  @returns true if successful.
	 */
	bool
	operator()(std::string const & from, std::string const & to) const
	{
		return move(from, to);
	}

	/** @returns a set of shell script commands to move file
	 *  @c from to @c to.
	 */
	std::string const
	sh_command(std::string const & from, std::string const & to) const
	{
		return sh_move(from, to);
	}

private:
	virtual bool
	move(std::string const & from, std::string const & to) const;

	virtual std::string const
	sh_move(std::string const & from, std::string const & to) const;
};


/**
 *  Specialization of the Mover concept that uses an external command
 *  to perform the movement of a file.
 *
 *  For example, an XFig .fig file can contain references to external
 *  picture files. If such a reference has a relative path, then moving
 *  the .fig file will require a transformation of the picture file
 *  reference if it is to be found by XFig.
 */
struct SpecialisedMover : public Mover {
	/** @c command should be of the form
	 *  <code>
	 *      sh $$s/move_fig.sh $$i $$o
	 *  </code>
	 *  where $$s is a placeholder for the lyx script directory,
	 *        $$i is a placeholder for the name of the file to be moved,
	 *        $$o is a placeholder for the name of the file after moving.
	 */
	SpecialisedMover(std::string const & command);

private:
	virtual bool
	move(std::string const & from, std::string const & to) const;

	virtual std::string const
	sh_move(std::string const & from, std::string const & to) const;

	std::string command_;
};


/**
 *  A singleton class to manage the store of (Mover)s.
 */
class Movers : boost::noncopyable {
public:
	// A singleton class
	static Movers & get();

	/** Register a specialised @c command to be used to move a file
	 *  of format @c fmt.
	 */
	void set(Format const & fmt, std::string const & command);

	/// @c returns the Mover registered for Format @c fmt.
	Mover const & operator()(Format const & fmt) const;

private:
	Movers();
	~Movers() {}

	Mover default_;
	typedef std::map<std::string, boost::shared_ptr<Mover> > SpecialsMap;
	SpecialsMap specials_;
};

#endif // MOVER_H

Reply via email to