#include "GraphicsCacheItem.h"
#include "GraphicsImage.h"
#include "GraphicsParams.h"
-#include "LoaderQueue.h"
+#include "GraphicsCache.h"
-#include <boost/bind.hpp>
+#include "support/debug.h"
+#include "support/Timeout.h"
+#include <boost/bind.hpp>
-using std::string;
+#include <set>
+#include <queue>
+using namespace std;
+using namespace lyx::support;
namespace lyx {
+namespace graphics {
+
+
+/////////////////////////////////////////////////////////////////////
+//
+// LoaderQueue
+//
+/////////////////////////////////////////////////////////////////////
+
+class LoaderQueue {
+public:
+ /// Use this to request that the item is loaded.
+ void touch(Cache::ItemPtr const & item);
+ /// Query whether the clock is ticking.
+ bool running() const;
+ ///get the and only instance of the class
+ static LoaderQueue & get();
+private:
+ /// This class is a singleton class... use LoaderQueue::get() instead
+ LoaderQueue();
+ /// The in-progress loading queue (elements are unique here).
+ list<Cache::ItemPtr> cache_queue_;
+ /// Used to make the insertion of new elements faster.
+ set<Cache::ItemPtr> cache_set_;
+ /// Newly touched elements go here. loadNext moves them to cache_queue_
+ queue<Cache::ItemPtr> bucket_;
+ ///
+ Timeout timer;
+ ///
+ bool running_;
+
+ /** This is the 'threaded' method, that does the loading in the
+ * background.
+ */
+ void loadNext();
+ ///
+ void startLoader();
+ ///
+ void stopLoader();
+};
+
+
+//static int s_numimages_ = 5;
+//static int s_millisecs_ = 500;
+
+static int s_numimages_ = 10;
+static int s_millisecs_ = 500;
+
+LoaderQueue & LoaderQueue::get()
+{
+ static LoaderQueue singleton;
+ return singleton;
+}
+
+
+void LoaderQueue::loadNext()
+{
+ LYXERR(Debug::GRAPHICS, "LoaderQueue: "
+ << cache_queue_.size() << " items in the queue");
+ int counter = s_numimages_;
+ while (cache_queue_.size() && counter--) {
+ Cache::ItemPtr ptr = cache_queue_.front();
+ cache_set_.erase(ptr);
+ cache_queue_.pop_front();
+ if (ptr->status() == WaitingToLoad)
+ ptr->startLoading();
+ }
+ if (cache_queue_.size()) {
+ startLoader();
+ } else {
+ stopLoader();
+ }
+}
+
+
+LoaderQueue::LoaderQueue() : timer(s_millisecs_, Timeout::ONETIME),
+ running_(false)
+{
+ timer.timeout.connect(boost::bind(&LoaderQueue::loadNext, this));
+}
+
+
+void LoaderQueue::startLoader()
+{
+ LYXERR(Debug::GRAPHICS, "LoaderQueue: waking up");
+ running_ = true ;
+ timer.setTimeout(s_millisecs_);
+ timer.start();
+}
+
+
+void LoaderQueue::stopLoader()
+{
+ timer.stop();
+ running_ = false ;
+ LYXERR(Debug::GRAPHICS, "LoaderQueue: I'm going to sleep");
+}
+
+
+bool LoaderQueue::running() const
+{
+ return running_ ;
+}
+
+
+void LoaderQueue::touch(Cache::ItemPtr const & item)
+{
+ if (! cache_set_.insert(item).second) {
+ list<Cache::ItemPtr>::iterator
+ it = cache_queue_.begin();
+ list<Cache::ItemPtr>::iterator
+ end = cache_queue_.end();
+
+ it = find(it, end, item);
+ if (it != end)
+ cache_queue_.erase(it);
+ }
+ cache_queue_.push_front(item);
+ if (!running_)
+ startLoader();
+}
-using support::FileName;
-namespace graphics {
+
+/////////////////////////////////////////////////////////////////////
+//
+// GraphicsLoader
+//
+/////////////////////////////////////////////////////////////////////
+
+typedef boost::shared_ptr<Image> ImagePtr;
class Loader::Impl : public boost::signals::trackable {
public:
*/
Cache::ItemPtr cached_item_;
/// We modify a local copy of the image once it is loaded.
- Image::ImagePtr image_;
+ ImagePtr image_;
/// This signal is emitted when the image loading status changes.
boost::signal<void()> signal_;
/// The connection of the signal StatusChanged
{}
-Loader::Loader(FileName const & file, DisplayType type)
+Loader::Loader(FileName const & file, bool display)
: pimpl_(new Impl)
{
- reset(file, type);
+ reset(file, display);
}
}
-void Loader::reset(FileName const & file, DisplayType type) const
+void Loader::reset(FileName const & file, bool display) const
{
Params params;
- params.display = type;
+ params.display = display;
pimpl_->resetParams(params);
pimpl_->resetFile(file);
}
+void Loader::reload() const
+{
+ pimpl_->cached_item_->startLoading();
+}
+
+
void Loader::startMonitoring() const
{
if (!pimpl_->cached_item_.get())
void Loader::Impl::createPixmap()
{
- if (!cached_item_.get() ||
- params_.display == NoDisplay || status_ != Loaded)
+ if (!params_.display || status_ != Loaded)
return;
- image_.reset(cached_item_->image()->clone());
+ if (!cached_item_.get()) {
+ LYXERR(Debug::GRAPHICS, "pixmap not cached yet");
+ return;
+ }
+
+ if (!cached_item_->image()) {
+ // There must have been a problem reading the file.
+ LYXERR(Debug::GRAPHICS, "Graphics file not loaded.");
+ return;
+ }
- // These do nothing if there's nothing to do
- image_->clip(params_);
- image_->rotate(params_);
- image_->scale(params_);
+ image_.reset(cached_item_->image()->clone());
bool const success = image_->setPixmap(params_);
if (status_ != WaitingToLoad)
return;
+ if (cached_item_->tryDisplayFormat()) {
+ status_ = Loaded;
+ createPixmap();
+ return;
+ }
+
LoaderQueue::get().touch(cached_item_);
}