diff --git a/src/buddies/unit_tests/buddies_main.cc b/src/buddies/unit_tests/buddies_main.cc
index a8bbd4e25..1f26d86f8 100644
--- a/src/buddies/unit_tests/buddies_main.cc
+++ b/src/buddies/unit_tests/buddies_main.cc
@@ -28,9 +28,8 @@
#include "rba.h"
#include "gsiDecl.h"
-// On Windows, ruby.h is not compatible with windows.h which is included by utHead - at least not if
-// windows.h is included before ruby.h ...
#include "tlUnitTest.h"
+#include "tlFileUtils.h"
void run_rubytest (tl::TestBase * /*_this*/, const std::string &fn)
{
diff --git a/src/layui/layui/rdbMarkerBrowserPage.cc b/src/layui/layui/rdbMarkerBrowserPage.cc
index 52bd2b58a..a5d93ce50 100644
--- a/src/layui/layui/rdbMarkerBrowserPage.cc
+++ b/src/layui/layui/rdbMarkerBrowserPage.cc
@@ -2001,9 +2001,10 @@ MarkerBrowserPage::update_info_text ()
info += "";
- if (item->image () != 0) {
+ QImage image = item->image ();
+ if (! image.isNull ()) {
info += "
Snapshot image (click to enlarge) 
|
";
- info_text->set_image (*item->image ());
+ info_text->set_image (image);
}
}
@@ -2802,7 +2803,7 @@ MarkerBrowserPage::remove_snapshot_button_clicked ()
if (selected_item->column () == 0) {
const rdb::Item *i = list_model->item (selected_item->row ());
if (i) {
- mp_database->set_item_image (i, 0);
+ mp_database->set_item_image (i, QImage ());
}
}
}
@@ -2830,7 +2831,7 @@ MarkerBrowserPage::snapshot_button_clicked ()
const rdb::Item *i = list_model->item (selected_item->row ());
if (i) {
- mp_database->set_item_image (i, new QImage (mp_view->get_screenshot ()));
+ mp_database->set_item_image (i, QImage (mp_view->get_screenshot ()));
markers_list->selectionModel ()->setCurrentIndex (*selected_item, QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows);
update_info_text ();
@@ -3125,8 +3126,8 @@ MarkerBrowserPage::info_anchor_clicked (const QUrl &link)
QModelIndex current = markers_list->selectionModel ()->currentIndex ();
const rdb::Item *i = list_model->item (current.row ());
- if (i && i->image () != 0) {
- MarkerBrowserSnapshotView *snapshot_view = new MarkerBrowserSnapshotView (this, *i->image ());
+ if (i && i->has_image ()) {
+ MarkerBrowserSnapshotView *snapshot_view = new MarkerBrowserSnapshotView (this, i->image ());
snapshot_view->exec ();
delete snapshot_view;
#if QT_VERSION < 0x040300
diff --git a/src/rdb/rdb/gsiDeclRdb.cc b/src/rdb/rdb/gsiDeclRdb.cc
index 1a410e670..838e0bc19 100644
--- a/src/rdb/rdb/gsiDeclRdb.cc
+++ b/src/rdb/rdb/gsiDeclRdb.cc
@@ -808,16 +808,19 @@ Class decl_RdbItem ("rdb", "RdbItem",
"@brief Sets the tags from a string\n"
"@param tags A comma-separated list of tags\n"
) +
-#if defined(HAVE_QT)
- gsi::method ("image_str", &rdb::Item::image_str,
+ gsi::method ("has_image?", &rdb::Item::has_image,
+ "@brief Gets a value indicating that the item has an image attached\n"
+ "See \\image_str how to obtain the image.\n\n"
+ "This method has been introduced in version 0.28.\n"
+ ) +
+ gsi::method ("image_str", &rdb::Item::image_str,
"@brief Gets the image associated with this item as a string\n"
- "@return A base64-encoded image file (usually in PNG format)\n"
+ "@return A base64-encoded image file (in PNG format)\n"
) +
gsi::method ("image_str=", &rdb::Item::set_image_str, gsi::arg ("image"),
"@brief Sets the image from a string\n"
"@param image A base64-encoded image file (preferably in PNG format)\n"
) +
-#endif
/* Not supported yet:
gsi::method ("multiplicity", &rdb::Item::multiplicity,
"@brief Gets the item's multiplicity\n"
diff --git a/src/rdb/rdb/rdb.cc b/src/rdb/rdb/rdb.cc
index 1187bbb27..013cefe7f 100644
--- a/src/rdb/rdb/rdb.cc
+++ b/src/rdb/rdb/rdb.cc
@@ -821,15 +821,7 @@ Item &Item::operator= (const Item &d)
m_visited = d.m_visited;
m_multiplicity = d.m_multiplicity;
m_tag_ids = d.m_tag_ids;
-
-#if defined(HAVE_QT)
- if (mp_image.get ()) {
- mp_image.reset (0);
- }
- if (d.mp_image.get ()) {
- mp_image.reset (new QImage (*d.mp_image));
- }
-#endif
+ m_image_str = d.m_image_str;
}
return *this;
@@ -952,48 +944,60 @@ Item::set_tag_str (const std::string &tags)
#if defined(HAVE_QT)
void
-Item::set_image (QImage *image)
+Item::set_image (const QImage &image)
{
- mp_image.reset (image);
-}
+ if (image.isNull ()) {
+
+ m_image_str.clear ();
-std::string
-Item::image_str () const
-{
- if (! mp_image.get ()) {
- return std::string ();
} else {
QByteArray img_data;
QBuffer img_io_device (&img_data);
- mp_image->save (&img_io_device, "PNG");
+ image.save (&img_io_device, "PNG");
- return std::string (img_data.toBase64 ().constData ());
+ m_image_str = std::string (img_data.toBase64 ().constData ());
}
}
-void
-Item::set_image_str (const std::string &s)
+const QImage
+Item::image () const
{
- if (s.empty ()) {
- set_image (0);
+ if (m_image_str.empty ()) {
+
+ return QImage ();
+
} else {
- QByteArray img_data (QByteArray::fromBase64 (QByteArray::fromRawData (s.c_str (), int (s.size ()))));
+ QByteArray img_data (QByteArray::fromBase64 (QByteArray::fromRawData (m_image_str.c_str (), int (m_image_str.size ()))));
- QImage *image = new QImage ();
- if (image->loadFromData (img_data)) {
- set_image (image);
- } else {
- delete image;
- set_image (0);
- }
+ QImage image;
+ image.loadFromData (img_data);
+ return image;
}
}
#endif
+bool
+Item::has_image () const
+{
+ return !m_image_str.empty ();
+}
+
+std::string
+Item::image_str () const
+{
+ return m_image_str;
+}
+
+void
+Item::set_image_str (const std::string &s)
+{
+ m_image_str = s;
+}
+
// ------------------------------------------------------------------------------------------
// Database implementation
@@ -1324,13 +1328,20 @@ Database::remove_item_tag (const Item *item, id_type tag)
#if defined(HAVE_QT)
void
-Database::set_item_image (const Item *item, QImage *image)
+Database::set_item_image (const Item *item, const QImage &image)
{
set_modified ();
const_cast - (item)->set_image (image);
}
#endif
+void
+Database::set_item_image_str (const Item *item, const std::string &image_str)
+{
+ set_modified ();
+ const_cast
- (item)->set_image_str (image_str);
+}
+
void
Database::set_item_multiplicity (const Item *item, size_t n)
{
diff --git a/src/rdb/rdb/rdb.h b/src/rdb/rdb/rdb.h
index f62637142..a8c513ab9 100644
--- a/src/rdb/rdb/rdb.h
+++ b/src/rdb/rdb/rdb.h
@@ -941,35 +941,37 @@ public:
#if defined(HAVE_QT)
/**
- * @brief Get the image object attached to this item
+ * @brief Gets the image object attached to this item
*
- * @return The image object or 0 if no object is attached
+ * @return The image object or an empty image if no image is attached
*/
- const QImage *image () const
- {
- return mp_image.get ();
- }
+ const QImage image () const;
/**
- * @brief Set an image for this item
- *
- * The image object will become owned by the item
+ * @brief Set the image for this item
*/
- void set_image (QImage *image);
+ void set_image (const QImage &image);
+#endif
/**
- * @brief Get an image as a string (base64 coded)
+ * @brief Gets a value indicating whether the item has an image
+ */
+ bool has_image () const;
+
+ /**
+ * @brief Gets the image as a string (PNG, base64 coded)
+ *
+ * Note: if neither PNG support for Qt are compiled in, this string will be empty
*/
std::string image_str () const;
/**
- * @brief Get an image from a string (base64 coded)
+ * @brief Gets the image from a string (PNG, base64 coded)
*
* If the image string is empty, the image will be cleared.
* If the image string is not valid, the image will also be cleared.
*/
void set_image_str (const std::string &s);
-#endif
/**
* @brief Get the database reference
@@ -998,9 +1000,7 @@ private:
bool m_visited;
std::vector m_tag_ids;
Database *mp_database;
-#if defined(HAVE_QT)
- std::unique_ptr mp_image;
-#endif
+ std::string m_image_str;
Item ();
@@ -2226,9 +2226,14 @@ public:
/**
* @brief Set the image of an item
*/
- void set_item_image (const Item *item, QImage *image);
+ void set_item_image (const Item *item, const QImage &image);
#endif
+ /**
+ * @brief Set the image string of an item
+ */
+ void set_item_image_str (const Item *item, const std::string &image_str);
+
/**
* @brief Set the multiplicity of an item
*/
diff --git a/src/rdb/rdb/rdbFile.cc b/src/rdb/rdb/rdbFile.cc
index 82ad16dc8..8006be4d5 100644
--- a/src/rdb/rdb/rdbFile.cc
+++ b/src/rdb/rdb/rdbFile.cc
@@ -106,9 +106,7 @@ make_rdb_structure (rdb::Database *rdb)
tl::make_member (&rdb::Item::cell_qname, &rdb::Item::set_cell_qname, "cell") +
tl::make_member (&rdb::Item::visited, &rdb::Item::set_visited, "visited") +
tl::make_member (&rdb::Item::multiplicity, &rdb::Item::set_multiplicity, "multiplicity") +
-#if defined(HAVE_QT)
tl::make_member (&rdb::Item::image_str, &rdb::Item::set_image_str, "image") +
-#endif
tl::make_element (&rdb::Item::values, &rdb::Item::set_values, "values",
tl::make_member (&rdb::Values::begin, &rdb::Values::end, &rdb::Values::add, "value", ValueConverter (rdb))
)
diff --git a/src/tl/tl/tlResources.cc b/src/tl/tl/tlResources.cc
index c37cb4e5d..f158eda62 100644
--- a/src/tl/tl/tlResources.cc
+++ b/src/tl/tl/tlResources.cc
@@ -146,7 +146,7 @@ tl::InputStream *get_resource (const char *name)
} else {
auto stream = new tl::InputStream (rr.first);
if (rr.second) {
- stream->inflate ();
+ stream->inflate_always ();
}
return stream;
}
diff --git a/src/tl/tl/tlResources.h b/src/tl/tl/tlResources.h
index 699e2089b..2c88e8644 100644
--- a/src/tl/tl/tlResources.h
+++ b/src/tl/tl/tlResources.h
@@ -81,8 +81,8 @@ TL_PUBLIC std::pair get_resource_reader (const char
/**
* @brief Get resource names matching a glob pattern
*
- * For example, find_resources("/group/*") will find resources below "group".
- * "*" also matches "/", so resources from subgroups will be listed too.
+ * For example, find_resources("/group*") will find resources whose name start with "group".
+ * "*" also matches "/"!
*/
TL_PUBLIC std::vector find_resources (const std::string &pattern);
diff --git a/src/tl/tl/tlStream.cc b/src/tl/tl/tlStream.cc
index 92077af57..80fa4ef1a 100644
--- a/src/tl/tl/tlStream.cc
+++ b/src/tl/tl/tlStream.cc
@@ -143,8 +143,39 @@ public:
// ---------------------------------------------------------------
// InputStream implementation
+namespace {
+
+/**
+ * @brief A dummy delegate to provide for the case of raw data stashed inside the stream itself
+ */
+class RawDataDelegate
+ : public InputStreamBase
+{
+public:
+ RawDataDelegate (const std::string &source)
+ : m_source (source)
+ { }
+
+ virtual size_t read (char *, size_t)
+ {
+ return 0;
+ }
+
+ virtual void reset () { }
+ virtual void close () { }
+
+ virtual std::string source () const { return m_source; }
+ virtual std::string absolute_path () const { return m_source; }
+ virtual std::string filename () const { return m_source; }
+
+public:
+ std::string m_source;
+};
+
+}
+
InputStream::InputStream (InputStreamBase &delegate)
- : m_pos (0), mp_bptr (0), mp_delegate (&delegate), m_owns_delegate (false), mp_inflate (0)
+ : m_pos (0), mp_bptr (0), mp_delegate (&delegate), m_owns_delegate (false), mp_inflate (0), m_inflate_always (false)
{
m_bcap = 4096; // initial buffer capacity
m_blen = 0;
@@ -152,7 +183,7 @@ InputStream::InputStream (InputStreamBase &delegate)
}
InputStream::InputStream (InputStreamBase *delegate)
- : m_pos (0), mp_bptr (0), mp_delegate (delegate), m_owns_delegate (true), mp_inflate (0)
+ : m_pos (0), mp_bptr (0), mp_delegate (delegate), m_owns_delegate (true), mp_inflate (0), m_inflate_always (false)
{
m_bcap = 4096; // initial buffer capacity
m_blen = 0;
@@ -160,7 +191,7 @@ InputStream::InputStream (InputStreamBase *delegate)
}
InputStream::InputStream (const std::string &abstract_path)
- : m_pos (0), mp_bptr (0), mp_delegate (0), m_owns_delegate (false), mp_inflate (0)
+ : m_pos (0), mp_bptr (0), mp_delegate (0), m_owns_delegate (false), mp_inflate (0), m_inflate_always (false)
{
m_bcap = 4096; // initial buffer capacity
m_blen = 0;
@@ -175,28 +206,30 @@ InputStream::InputStream (const std::string &abstract_path)
#if defined(HAVE_QT)
QResource res (tl::to_qstring (abstract_path));
- if (res.size () > 0) {
-
- QByteArray data;
-#if QT_VERSION >= 0x60000
- if (res.compressionAlgorithm () == QResource::ZlibCompression) {
-#else
- if (res.isCompressed ()) {
-#endif
- data = qUncompress ((const unsigned char *)res.data (), (int)res.size ());
- } else {
- data = QByteArray ((const char *)res.data (), (int)res.size ());
- }
-
- mp_buffer = new char[data.size ()];
- memcpy (mp_buffer, data.constData (), data.size ());
-
- mp_bptr = mp_buffer;
- m_bcap = data.size ();
- m_blen = m_bcap;
-
+ if (res.size () == 0) {
+ throw tl::Exception (tl::to_string (tr ("Resource not found: ")) + abstract_path);
}
+ QByteArray data;
+#if QT_VERSION >= 0x60000
+ if (res.compressionAlgorithm () == QResource::ZlibCompression) {
+#else
+ if (res.isCompressed ()) {
+#endif
+ data = qUncompress ((const unsigned char *)res.data (), (int)res.size ());
+ } else {
+ data = QByteArray ((const char *)res.data (), (int)res.size ());
+ }
+
+ mp_buffer = new char[data.size ()];
+ memcpy (mp_buffer, data.constData (), data.size ());
+
+ mp_bptr = mp_buffer;
+ m_bcap = data.size ();
+ m_blen = m_bcap;
+
+ mp_delegate = new RawDataDelegate (abstract_path);
+
#else
std::pair rr = tl::get_resource_reader (ex.get ());
@@ -240,7 +273,7 @@ InputStream::InputStream (const std::string &abstract_path)
m_owns_delegate = true;
if (needs_inflate) {
- inflate ();
+ inflate_always ();
}
}
@@ -441,6 +474,13 @@ InputStream::inflate ()
mp_inflate = new tl::InflateFilter (*this);
}
+void
+InputStream::inflate_always ()
+{
+ m_inflate_always = true;
+ reset ();
+}
+
void
InputStream::close ()
{
@@ -468,6 +508,8 @@ InputStream::reset ()
} else {
+ tl_assert (mp_delegate != 0);
+
mp_delegate->reset ();
m_pos = 0;
@@ -481,6 +523,10 @@ InputStream::reset ()
mp_buffer = new char [m_bcap];
}
+
+ if (m_inflate_always) {
+ inflate ();
+ }
}
// ---------------------------------------------------------------
diff --git a/src/tl/tl/tlStream.h b/src/tl/tl/tlStream.h
index 0747a4b7e..9cd53a983 100644
--- a/src/tl/tl/tlStream.h
+++ b/src/tl/tl/tlStream.h
@@ -466,6 +466,15 @@ public:
*/
void inflate ();
+ /**
+ * @brief Enables "inflate" right from the beginning
+ *
+ * Contrary to "inflate" (which is temporary), this version enables
+ * decompression right from the beginning of the file. It does a "reset"
+ * implicitly.
+ */
+ void inflate_always ();
+
/**
* @brief Obtain the current file position
*/
@@ -557,6 +566,7 @@ private:
// inflate support
InflateFilter *mp_inflate;
+ bool m_inflate_always;
// No copying currently
InputStream (const InputStream &);
diff --git a/src/unit_tests/unit_test_main.cc b/src/unit_tests/unit_test_main.cc
index 4bc19ed7f..0f66e0952 100644
--- a/src/unit_tests/unit_test_main.cc
+++ b/src/unit_tests/unit_test_main.cc
@@ -607,6 +607,14 @@ main_cont (int &argc, char **argv)
tl::set_continue_flag (continue_flag);
tl::set_debug_mode (debug_mode);
+ // set some global variables
+ if (rba::RubyInterpreter::instance ()) {
+ rba::RubyInterpreter::instance ()->define_variable ("ut_inst_path", tl::get_inst_path ());
+ }
+ if (pya::PythonInterpreter::instance ()) {
+ pya::PythonInterpreter::instance ()->define_variable ("ut_inst_path", tl::get_inst_path ());
+ }
+
FILE *output_file = 0;
try {
diff --git a/testdata/buddies/buddies.rb b/testdata/buddies/buddies.rb
index 7658e6007..0864169cd 100644
--- a/testdata/buddies/buddies.rb
+++ b/testdata/buddies/buddies.rb
@@ -32,7 +32,7 @@ load("test_prologue.rb")
class Buddies_TestClass < TestBase
def buddy_bin(name)
- file = File.join(RBA::Application::instance.inst_path, name)
+ file = File.join($ut_inst_path, name)
return file
end
diff --git a/testdata/ruby/dbGlyphs.rb b/testdata/ruby/dbGlyphs.rb
index c7b5792c8..75bb1e3f2 100644
--- a/testdata/ruby/dbGlyphs.rb
+++ b/testdata/ruby/dbGlyphs.rb
@@ -69,7 +69,7 @@ class DBGlyph_TestClass < TestBase
tg.load_from_resource(":/fonts/does_not_exist.gds")
assert_equal(false, true)
rescue => ex
- assert_equal(ex.to_s, "Unable to load font resource from :/fonts/does_not_exist.gds in TextGenerator::load_from_resource")
+ assert_equal(ex.to_s, "Resource not found: :/fonts/does_not_exist.gds in TextGenerator::load_from_resource")
end
end