[glom] Python button scripts: Add show_table_details() and show_table_list().
- From: Murray Cumming <murrayc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glom] Python button scripts: Add show_table_details() and show_table_list().
- Date: Sun, 28 Feb 2010 01:29:59 +0000 (UTC)
commit 8a1511ebc6c607892c8ba734b9ea0d8b88a91156
Author: Murray Cumming <murrayc murrayc com>
Date: Sun Feb 28 02:29:41 2010 +0100
Python button scripts: Add show_table_details() and show_table_list().
* Makefile_libglom.am:
* glom/python_embed/python_module/py_glom_module.cc:
* glom/libglom/python_embed/py_glom_ui.[h|cc]: Added a PyGlomUI object
that can be passed to python functions in addition to the record object,
with methods to navigate in the UI. So far there is just
show_table_details() and show_table_list().
* glom/glom_developer.glade: Script editor window: Mention the extra ui
parameter.
* glom/python_embed/glom_python.[h|cc]: Add a callback object parameter so
scripts can tell the caller to change things in the UI.
* glom/frame_glom.h: Made show_table() public so that the Application can
call it.
* glom/application.[h|cc]: Add show_table_details() and add_show_list()
methods for the callbacks to call.
* glom/mode_data/box_data.[h|cc]: Handle the callback signals, to actually do
the navigation when a python script requests it.
* glom/mode_design/layout/layout_item_dialogs/dialog_buttonscript.cc: Adapted.
ChangeLog | 22 ++
Makefile_libglom.am | 2 +
glom/application.cc | 17 +
glom/application.h | 5 +-
glom/frame_glom.h | 14 +-
glom/glom_developer.glade | 2 +-
glom/libglom/connectionpool.cc | 2 +-
glom/libglom/python_embed/py_glom_record.h | 2 +
glom/libglom/python_embed/py_glom_ui.cc | 72 +++++
glom/libglom/python_embed/py_glom_ui.h | 72 +++++
glom/mode_data/box_data.cc | 29 ++-
glom/mode_data/box_data.h | 6 +-
.../layout_item_dialogs/dialog_buttonscript.cc | 4 +-
glom/python_embed/glom_python.cc | 316 +++++++++++---------
glom/python_embed/glom_python.h | 13 +-
glom/python_embed/python_module/py_glom_module.cc | 6 +
16 files changed, 418 insertions(+), 166 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 0761c41..7cffdd1 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,25 @@
+2010-02-28 Murray Cumming <murrayc murrayc com>
+
+ Python button scripts: Add show_table_details() and show_table_list().
+
+ * Makefile_libglom.am:
+ * glom/python_embed/python_module/py_glom_module.cc:
+ * glom/libglom/python_embed/py_glom_ui.[h|cc]: Added a PyGlomUI object
+ that can be passed to python functions in addition to the record object,
+ with methods to navigate in the UI. So far there is just
+ show_table_details() and show_table_list().
+ * glom/glom_developer.glade: Script editor window: Mention the extra ui
+ parameter.
+ * glom/python_embed/glom_python.[h|cc]: Add a callback object parameter so
+ scripts can tell the caller to change things in the UI.
+ * glom/frame_glom.h: Made show_table() public so that the Application can
+ call it.
+ * glom/application.[h|cc]: Add show_table_details() and add_show_list()
+ methods for the callbacks to call.
+ * glom/mode_data/box_data.[h|cc]: Handle the callback signals, to actually do
+ the navigation when a python script requests it.
+ * glom/mode_design/layout/layout_item_dialogs/dialog_buttonscript.cc: Adapted.
+
2010-02-27 Murray Cumming <murrayc murrayc com>
Python: Prevent field calculations from changing the data in other fields.
diff --git a/Makefile_libglom.am b/Makefile_libglom.am
index a8aa118..63fdc75 100644
--- a/Makefile_libglom.am
+++ b/Makefile_libglom.am
@@ -148,6 +148,8 @@ glom_libglom_libglom_1_14_la_SOURCES = \
glom/libglom/python_embed/py_glom_related.h \
glom/libglom/python_embed/py_glom_relatedrecord.cc \
glom/libglom/python_embed/py_glom_relatedrecord.h \
+ glom/libglom/python_embed/py_glom_ui.cc \
+ glom/libglom/python_embed/py_glom_ui.h \
glom/libglom/python_embed/pygdavalue_conversions.cc \
glom/libglom/python_embed/pygdavalue_conversions.h
diff --git a/glom/application.cc b/glom/application.cc
index eb08b2a..b4fb50d 100644
--- a/glom/application.cc
+++ b/glom/application.cc
@@ -2539,6 +2539,23 @@ void App_Glom::update_window_title()
#endif //GLOM_ENABLE_MAEMO
}
+void App_Glom::show_table_details(const Glib::ustring& table_name, const Gnome::Gda::Value& primary_key_value)
+{
+ if(!m_pFrame)
+ return;
+
+ m_pFrame->show_table(table_name, primary_key_value);
+}
+
+void App_Glom::show_table_list(const Glib::ustring& table_name)
+{
+ if(!m_pFrame)
+ return;
+
+ m_pFrame->show_table(table_name);
+}
+
+
} //namespace Glom
diff --git a/glom/application.h b/glom/application.h
index 6ff2a6e..c7c30a9 100644
--- a/glom/application.h
+++ b/glom/application.h
@@ -105,7 +105,10 @@ public:
///Whether to show the generated SQL queries on stdout, for debugging.
void set_show_sql_debug(bool val = true);
-
+
+ void show_table_details(const Glib::ustring& table_name, const Gnome::Gda::Value& primary_key_value);
+ void show_table_list(const Glib::ustring& table_name);
+
static App_Glom* get_application();
protected:
diff --git a/glom/frame_glom.h b/glom/frame_glom.h
index a5afb06..26bec8c 100644
--- a/glom/frame_glom.h
+++ b/glom/frame_glom.h
@@ -186,6 +186,13 @@ public:
Glib::ustring get_shown_table_name() const;
+ /** Show the table, possibly selecting a particular record, possibly showing that in the details tab.
+ *
+ * @param table_name The database table to show.
+ * @param primary_key_value_for_details If specified, switch to the details view, and show this record.
+ */
+ void show_table(const Glib::ustring& table_name, const Gnome::Gda::Value& primary_key_value_for_details = Gnome::Gda::Value());
+
protected:
@@ -200,13 +207,6 @@ protected:
*/
void show_table_allow_empty(const Glib::ustring& table_name, const Gnome::Gda::Value& primary_key_value_for_details = Gnome::Gda::Value());
- /** Show the table, possibly selecting a particular record, possibly showing that in the details tab.
- *
- * @param table_name The database table to show.
- * @param primary_key_value_for_details If specified, switch to the details view, and show this record.
- */
- void show_table(const Glib::ustring& table_name, const Gnome::Gda::Value& primary_key_value_for_details = Gnome::Gda::Value());
-
/** Hide the currently shown table so that no table is shown.
*/
void show_no_table();
diff --git a/glom/glom_developer.glade b/glom/glom_developer.glade
index cfe5ada..4f78e6a 100644
--- a/glom/glom_developer.glade
+++ b/glom/glom_developer.glade
@@ -1089,7 +1089,7 @@
<property name="xalign">0</property>
<property name="label">import glom
-<b>def on_button_clicked(record):</b></property>
+<b>def on_button_clicked(record, ui):</b></property>
<property name="use_markup">True</property>
</object>
<packing>
diff --git a/glom/libglom/connectionpool.cc b/glom/libglom/connectionpool.cc
index 6152b89..6f793da 100644
--- a/glom/libglom/connectionpool.cc
+++ b/glom/libglom/connectionpool.cc
@@ -535,7 +535,7 @@ bool ConnectionPool::startup(const SlotProgress& slot_progress, bool network_sha
//If we crash while running (unlikely, hopefully), then try to cleanup.
//Comment this out if you want to see the backtrace in a debugger.
- previous_sig_handler = signal(SIGSEGV, &on_linux_signal);
+ //previous_sig_handler = signal(SIGSEGV, &on_linux_signal);
return true;
}
diff --git a/glom/libglom/python_embed/py_glom_record.h b/glom/libglom/python_embed/py_glom_record.h
index e3e7f84..eaec45e 100644
--- a/glom/libglom/python_embed/py_glom_record.h
+++ b/glom/libglom/python_embed/py_glom_record.h
@@ -70,6 +70,8 @@ public:
type_map_field_values m_map_field_values;
Glib::RefPtr<Gnome::Gda::Connection> m_connection;
+
+private:
bool m_read_only;
};
diff --git a/glom/libglom/python_embed/py_glom_ui.cc b/glom/libglom/python_embed/py_glom_ui.cc
new file mode 100644
index 0000000..91a8084
--- /dev/null
+++ b/glom/libglom/python_embed/py_glom_ui.cc
@@ -0,0 +1,72 @@
+/* Glom
+ *
+ * Copyright (C) 2001-2005 Murray Cumming
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <libglom/python_embed/py_glom_ui.h>
+#include <libglom/python_embed/pygdavalue_conversions.h>
+
+
+namespace Glom
+{
+
+PythonUICallbacks::type_signal_show_table_details PythonUICallbacks::signal_show_table_details()
+{
+ return m_signal_show_table_details;
+}
+
+PythonUICallbacks::type_signal_show_table_list PythonUICallbacks::signal_show_table_list()
+{
+ return m_signal_show_table_list;
+}
+
+PyGlomUI::PyGlomUI()
+: m_callbacks(0)
+{
+}
+PyGlomUI::PyGlomUI(const PythonUICallbacks& callbacks)
+: m_callbacks(&callbacks)
+{
+}
+
+PyGlomUI::~PyGlomUI()
+{
+}
+
+void PyGlomUI::show_table_details(const std::string& table_name, const boost::python::object& primary_key_value)
+{
+ if(!m_callbacks)
+ return;
+
+ Gnome::Gda::Value gda_primary_key_value;
+
+ GValue value = {0, {{0}}};
+ const bool test = glom_pygda_value_from_pyobject(&value, primary_key_value);
+ if(test && G_IS_VALUE(&value))
+ gda_primary_key_value = Gnome::Gda::Value(&value);
+
+ m_callbacks->m_signal_show_table_details.emit(table_name, gda_primary_key_value);
+}
+
+void PyGlomUI::show_table_list(const std::string& table_name)
+{
+ if(m_callbacks)
+ m_callbacks->m_signal_show_table_list.emit(table_name);
+}
+
+} //namespace Glom
diff --git a/glom/libglom/python_embed/py_glom_ui.h b/glom/libglom/python_embed/py_glom_ui.h
new file mode 100644
index 0000000..0424dbd
--- /dev/null
+++ b/glom/libglom/python_embed/py_glom_ui.h
@@ -0,0 +1,72 @@
+/* Glom
+ *
+ * Copyright (C) 2001-2005 Murray Cumming
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef GLOM_PYTHON_GLOM_UI_H
+#define GLOM_PYTHON_GLOM_UI_H
+
+#include <boost/python.hpp>
+
+#include <libglom/document/document.h>
+#include <libglom/data_structure/field.h>
+#include <glibmm/ustring.h>
+
+namespace Glom
+{
+
+/** UI code should connect to the signals to respond when Python code
+ * request a change in the UI.
+ */
+class PythonUICallbacks : public sigc::trackable
+{
+public:
+ /** For example,
+ * void on_show_details(const Glib::ustring& table_name, const Gnome::Gda::Value& primary_key_value);
+ */
+ typedef sigc::signal<void, const Glib::ustring&, const Gnome::Gda::Value&> type_signal_show_table_details;
+ type_signal_show_table_details signal_show_table_details();
+
+ typedef sigc::signal<void, const Glib::ustring&> type_signal_show_table_list;
+ type_signal_show_table_list signal_show_table_list();
+
+ friend class PyGlomUI;
+
+private:
+ type_signal_show_table_details m_signal_show_table_details;
+ type_signal_show_table_list m_signal_show_table_list;
+};
+
+class PyGlomUI
+{
+public:
+ //A default constructor seems to be necessary for boost::python
+ PyGlomUI();
+ explicit PyGlomUI(const PythonUICallbacks& callbacks);
+ ~PyGlomUI();
+
+ void show_table_details(const std::string& table_name, const boost::python::object& primary_key_value);
+ void show_table_list(const std::string& table_name);
+
+private:
+ const PythonUICallbacks* m_callbacks;
+};
+
+} //namespace Glom
+
+#endif //GLOM_PYTHON_GLOM_UI_H
diff --git a/glom/mode_data/box_data.cc b/glom/mode_data/box_data.cc
index 82d11aa..f875a1e 100644
--- a/glom/mode_data/box_data.cc
+++ b/glom/mode_data/box_data.cc
@@ -26,6 +26,7 @@
#include <libglom/data_structure/layout/layoutitem_field.h>
#include <glom/glom_privs.h>
#include <glom/python_embed/glom_python.h>
+#include <glom/application.h>
#include <algorithm> //For std::find()
#include <libglom/libglom_config.h>
#include <glibmm/i18n.h>
@@ -350,6 +351,24 @@ Glib::ustring Box_Data::get_layout_name() const
return m_layout_name;
}
+void Box_Data::on_python_requested_show_table_details(const Glib::ustring& table_name, const Gnome::Gda::Value& primary_key_value)
+{
+ std::cout << "debug: on_python_requested_show_table_details(): " << table_name << ", pk value: " << primary_key_value.to_string() << std::endl;
+
+ App_Glom* app = App_Glom::get_application();
+ if(app)
+ app->show_table_details(table_name, primary_key_value);
+}
+
+void Box_Data::on_python_requested_show_table_list(const Glib::ustring& table_name)
+{
+ //std::cout << "debug: on_python_requested_show_table_list(): " << table_name << std::endl;
+
+ App_Glom* app = App_Glom::get_application();
+ if(app)
+ app->show_table_list(table_name);
+}
+
void Box_Data::execute_button_script(const sharedptr<const LayoutItem_Button>& layout_item, const Gnome::Gda::Value& primary_key_value)
{
const sharedptr<Field> field_primary_key = get_field_primary_key();
@@ -365,11 +384,19 @@ void Box_Data::execute_button_script(const sharedptr<const LayoutItem_Button>& l
{
#endif // GLIBMM_EXCEPTIONS_ENABLED
+ //Allow this UI to respond to UI change requests from the Python code:
+ PythonUICallbacks callbacks;
+ callbacks.signal_show_table_details().connect(
+ sigc::mem_fun(*this, &Box_Data::on_python_requested_show_table_details));
+ callbacks.signal_show_table_list().connect(
+ sigc::mem_fun(*this, &Box_Data::on_python_requested_show_table_list));
+
glom_execute_python_function_implementation(layout_item->get_script(),
field_values, //TODO: Maybe use the field's type here.
get_document(),
get_table_name(), field_primary_key, primary_key_value,
- sharedconnection->get_gda_connection());
+ sharedconnection->get_gda_connection(),
+ callbacks);
#ifndef GLIBMM_EXCEPTIONS_ENABLED
}
#endif // !GLIBMM_EXCEPTIONS_ENABLED
diff --git a/glom/mode_data/box_data.h b/glom/mode_data/box_data.h
index 9555e15..174f7f8 100644
--- a/glom/mode_data/box_data.h
+++ b/glom/mode_data/box_data.h
@@ -110,7 +110,11 @@ protected:
//Signal handlers:
virtual void on_Button_Find(); //only used by _Find sub-classes. Should be MI.
-
+
+ //Signal handlers for the PyGlomUI callbacks:
+ void on_python_requested_show_table_details(const Glib::ustring& table_name, const Gnome::Gda::Value& primary_key_value);
+ void on_python_requested_show_table_list(const Glib::ustring& table_name);
+
static Glib::ustring xslt_process(const xmlpp::Document& xml_document, const std::string& filepath_xslt);
#ifndef GLOM_ENABLE_CLIENT_ONLY
diff --git a/glom/mode_design/layout/layout_item_dialogs/dialog_buttonscript.cc b/glom/mode_design/layout/layout_item_dialogs/dialog_buttonscript.cc
index 6885d7f..ecce872 100644
--- a/glom/mode_design/layout/layout_item_dialogs/dialog_buttonscript.cc
+++ b/glom/mode_design/layout/layout_item_dialogs/dialog_buttonscript.cc
@@ -116,12 +116,14 @@ void Dialog_ButtonScript::on_button_test()
//We need the connection when we run the script, so that the script may use it.
sharedptr<SharedConnection> sharedconnection = connect_to_server(this /* parent window */);
+ PythonUICallbacks callbacks;
glom_execute_python_function_implementation(calculation,
field_values, //TODO: Maybe use the field's type here.
document,
m_table_name,
sharedptr<Field>(), Gnome::Gda::Value(), // primary key - only used when setting values in the DB, which we would not encourage in a test.
- sharedconnection->get_gda_connection());
+ sharedconnection->get_gda_connection(),
+ callbacks);
}
} //namespace Glom
diff --git a/glom/python_embed/glom_python.cc b/glom/python_embed/glom_python.cc
index 44bd9a3..dd91d98 100644
--- a/glom/python_embed/glom_python.cc
+++ b/glom/python_embed/glom_python.cc
@@ -21,6 +21,7 @@
#include <config.h>
//We need to include this before anything else, to avoid redefinitions:
#include <libglom/python_embed/py_glom_record.h>
+#include <libglom/python_embed/py_glom_ui.h>
#include <libglom/python_embed/pygdavalue_conversions.h>
#include <boost/python.hpp>
@@ -163,31 +164,11 @@ bool gda_python_module_is_available()
return module_glom != 0;
}
-
-
-void glom_execute_python_function_implementation(const Glib::ustring& func_impl,
- const type_map_fields& field_values,
+static boost::python::object glom_python_call(Field::glom_field_type result_type,
Document* pDocument,
- const Glib::ustring& table_name,
- const sharedptr<const Field>& key_field,
- const Gnome::Gda::Value& key_field_value,
- const Glib::RefPtr<Gnome::Gda::Connection>& opened_connection)
-{
- glom_evaluate_python_function_implementation(Field::TYPE_TEXT, func_impl,
- field_values, pDocument,
- table_name, key_field, key_field_value,
- opened_connection, false /* not read-only */);
-}
-
-Gnome::Gda::Value glom_evaluate_python_function_implementation(Field::glom_field_type result_type,
- const Glib::ustring& func_impl,
- const type_map_fields& field_values,
- Document* pDocument,
- const Glib::ustring& table_name,
- const sharedptr<const Field>& key_field,
- const Gnome::Gda::Value& key_field_value,
- const Glib::RefPtr<Gnome::Gda::Connection>& opened_connection,
- bool read_only)
+ const Glib::ustring& func_impl,
+ const boost::python::object& param1,
+ const boost::python::object& param2 = boost::python::object())
{
//std::cout << "glom_evaluate_python_function_implementation()" << std::endl;
//for(type_map_fields::const_iterator iter = field_values.begin(); iter != field_values.end(); ++iter)
@@ -214,7 +195,14 @@ Gnome::Gda::Value glom_evaluate_python_function_implementation(Field::glom_field
//prefix the def line:
const Glib::ustring func_name = "glom_calc_field_value";
- func_def = "def " + func_name + "(record):\n import glom_" GLOM_ABI_VERSION_UNDERLINED "\n import gda\n" + func_def;
+ Glib::ustring func_signature;
+ if(!param2.ptr())
+ func_signature = func_name + "(record)";
+ else
+ func_signature = func_name + "(record, ui)";
+
+ func_def = "def " + func_signature + ":\n import glom_" GLOM_ABI_VERSION_UNDERLINED "\n import gda\n" + func_def;
+
//We did this in main(): Py_Initialize();
boost::python::object pMain = boost::python::import("__main__");
@@ -225,7 +213,7 @@ Gnome::Gda::Value glom_evaluate_python_function_implementation(Field::glom_field
{
std::cerr << "glom_evaluate_python_function_implementation(): pDict is null" << std::endl;
ShowTrace();
- return valueResult;
+ return boost::python::object();
}
//Allow the function to import from our script library:
@@ -261,7 +249,7 @@ Gnome::Gda::Value glom_evaluate_python_function_implementation(Field::glom_field
if(!module_glom)
{
g_warning("Could not import python glom module.");
- return valueResult; // don't crash
+ return boost::python::object(); // don't crash
}
//TODO: Is this necessary?
@@ -269,7 +257,7 @@ Gnome::Gda::Value glom_evaluate_python_function_implementation(Field::glom_field
if(!module_gda)
{
g_warning("Could not import python gda module.");
- return valueResult;
+ return boost::python::object();
}
//Create the function definition:
@@ -299,164 +287,196 @@ Gnome::Gda::Value glom_evaluate_python_function_implementation(Field::glom_field
{
std::cerr << "glom_evaluate_python_function_implementation(): boost::python::exec() threw error_already_set when using text= " << std::endl << func_def << std::endl;
ShowTrace();
- return valueResult;
+ return boost::python::object();
}
if(!pyValue.ptr())
{
std::cerr << "glom_evaluate_python_function_implementation(): boost::python::exec failed." << std::endl;
ShowTrace();
- return valueResult;
+ return boost::python::object();
}
//Call the function:
+ boost::python::object pFunc;
+ try
+ {
+ pFunc = pDict[func_name.c_str()];
+ }
+ catch(const boost::python::error_already_set& ex)
+ {
+ std::cerr << "glom_evaluate_python_function_implementation(): pDict[func_name] threw error_already_set when func_name= " << std::endl << func_name << std::endl;
+ ShowTrace();
+ return boost::python::object();
+ }
+
+ if(!pFunc.ptr())
{
- boost::python::object pFunc;
- try
+ std::cerr << "glom_evaluate_python_function_implementation(): pDict[func_name] failed." << std::endl;
+ HandlePythonError();
+ return boost::python::object();
+ }
+
+ if(!PyCallable_Check(pFunc.ptr()))
+ {
+ HandlePythonError();
+ g_warning("pFunc is not callable.");
+ return boost::python::object();
+ }
+
+ //Call the function with the parameters:
+ boost::python::object pyResultCpp;
+
+ try
+ {
+ if(!param2.ptr())
{
- pFunc = pDict[func_name.c_str()];
+ pyResultCpp = pFunc(param1);
}
- catch(const boost::python::error_already_set& ex)
+ else
{
- std::cerr << "glom_evaluate_python_function_implementation(): pDict[func_name] threw error_already_set when func_name= " << std::endl << func_name << std::endl;
- ShowTrace();
- return valueResult;
+ pyResultCpp = pFunc(param1, param2);
}
+ }
+ catch(const boost::python::error_already_set& ex)
+ {
+ std::cerr << "Glom: Exception caught from pFunc(objRecord). func_name=" << std::endl << func_name << std::endl;
+ ShowTrace();
+ }
- if(!pFunc.ptr())
- {
- std::cerr << "glom_evaluate_python_function_implementation(): pDict[func_name] failed." << std::endl;
- HandlePythonError();
- return valueResult;
- }
+ if(!(pyResultCpp.ptr()))
+ {
+ g_warning("pyResult.ptr() was null");
+ HandlePythonError();
+ }
+
+ //TODO: Why do we do this?
+ Py_FlushLine();
+ PyErr_Clear();
+
+ //We did this in main(): Py_Finalize();
- if(!PyCallable_Check(pFunc.ptr()))
- {
- HandlePythonError();
- g_warning("pFunc is not callable.");
- return valueResult;
- }
+ return pyResultCpp;
+}
- //The function's parameter:
+void glom_execute_python_function_implementation(const Glib::ustring& func_impl,
+ const type_map_fields& field_values,
+ Document* pDocument,
+ const Glib::ustring& table_name,
+ const sharedptr<const Field>& key_field,
+ const Gnome::Gda::Value& key_field_value,
+ const Glib::RefPtr<Gnome::Gda::Connection>& opened_connection,
+ const PythonUICallbacks& callbacks)
+{
+ boost::python::object objRecord(new PyGlomRecord);
+ boost::python::extract<PyGlomRecord*> extractor(objRecord);
+ if(!extractor.check())
+ {
+ std::cerr << ("extract<PyGlomRecord*> failed.") << std::endl;
+ }
+
+ PyGlomRecord* pParam = extractor;
+ if(pParam)
+ {
+ //Fill the record's details:
+ PyGlomRecord_SetFields(pParam, field_values, pDocument, table_name, key_field, key_field_value, opened_connection);
+ pParam->set_read_only();
+ }
+
+ //Pass an additional ui parameter for use by scripts:
+ boost::python::object objUI(new PyGlomUI(callbacks));
- //PyObject* pParam = PyString_FromString("test value"); //This test did not need the extra ref.
+ glom_python_call(Field::TYPE_TEXT, pDocument, func_impl, objRecord, objUI);
+}
- boost::python::object objRecord(new PyGlomRecord);
- boost::python::extract<PyGlomRecord*> extractor(objRecord);
- if(!extractor.check())
+Gnome::Gda::Value glom_evaluate_python_function_implementation(Field::glom_field_type result_type,
+ const Glib::ustring& func_impl,
+ const type_map_fields& field_values,
+ Document* pDocument,
+ const Glib::ustring& table_name,
+ const sharedptr<const Field>& key_field,
+ const Gnome::Gda::Value& key_field_value,
+ const Glib::RefPtr<Gnome::Gda::Connection>& opened_connection)
+{
+ boost::python::object objRecord(new PyGlomRecord);
+ boost::python::extract<PyGlomRecord*> extractor(objRecord);
+ if(!extractor.check())
+ {
+ std::cerr << ("extract<PyGlomRecord*> failed.") << std::endl;
+ return Gnome::Gda::Value();
+ }
+
+ PyGlomRecord* pParam = extractor;
+ if(pParam)
+ {
+ //Fill the record's details:
+ PyGlomRecord_SetFields(pParam, field_values, pDocument, table_name, key_field, key_field_value, opened_connection);
+ }
+
+ const boost::python::object pyResultCpp = glom_python_call(result_type, pDocument, func_impl, objRecord);
+
+ //Deal with the various possible return types:
+ Gnome::Gda::Value valueResult;
+ bool object_is_gda_value = false;
+
+ GValue value = {0, {{0}}};
+ const bool test = glom_pygda_value_from_pyobject(&value, pyResultCpp);
+
+ if(test)
+ object_is_gda_value = true;
+
+ if(object_is_gda_value && G_IS_VALUE(&value))
+ {
+ valueResult = Gnome::Gda::Value(&value);
+ //Make sure that the value is of the expected Gda type:
+ //TODO_Performance:
+ valueResult = Glom::Conversions::convert_value(valueResult, result_type);
+ //std::cout << "DEBUG: glom_evaluate_python_function_implementation(): valueResult Gda type=" << g_type_name(valueResult.get_value_type()) << std::endl;
+ g_value_unset(&value);
+ }
+ else
+ {
+ //g_warning("debug: pyResult is not a gda.value");
+
+ //For instance, if one of the fields was empty, then the calculation might want to return an empty value,
+ //instead of returning 0.
+ if(pyResultCpp == boost::python::object()) //Check if it is PyNone
{
- std::cerr << ("extract<PyGlomRecord*> failed.") << std::endl;
- return valueResult;
+ //The result should be an appropriate empty value for this field type:
+ valueResult = Conversions::get_empty_value(result_type);
+ //std::cout << "DEBUG: glom_evaluate_python_function_implementation(): empty value Gda type=" << g_type_name(valueResult.get_value_type()) << std::endl;
}
-
- PyGlomRecord* pParam = extractor;
- if(pParam)
+ else
{
- //Fill the record's details:
- PyGlomRecord_SetFields(pParam, field_values, pDocument, table_name, key_field, key_field_value, opened_connection);
- if(read_only)
- pParam->set_read_only();
-
- //Call the function with this parameter:
- boost::python::object pyResultCpp;
+ //TODO: Handle numeric/date/time types:
+ //(though I don't think this code is ever reached. murrayc)
+ //Treat this as a string or something that can be converted to a string:
+ const char* pchResult = 0;
try
{
- pyResultCpp = pFunc(objRecord);
+ pchResult = boost::python::extract<const char*>(pyResultCpp);
}
catch(const boost::python::error_already_set& ex)
{
- std::cerr << "Glom: Exception caught from pFunc(objRecord). func_name=" << std::endl << func_name << std::endl;
+ std::cerr << "Glom: Exception caught from boost::python::extract() while converting result to a const char*." << std::endl;
ShowTrace();
+ return valueResult;
}
- if(!(pyResultCpp.ptr()))
+ if(pchResult)
{
- g_warning("pyResult.ptr() was null");
- HandlePythonError();
+ bool success = false;
+ valueResult = Conversions::parse_value(result_type, pchResult, success, true /* iso_format */);
+ std::cout << "DEBUG: glom_evaluate_python_function_implementation(): parsed value Gda type=" << g_type_name(valueResult.get_value_type()) << std::endl;
}
else
- {
- //Deal with the various possible return types:
- bool object_is_gda_value = false;
-
- GValue value = {0, {{0}}};
- const bool test = glom_pygda_value_from_pyobject(&value, pyResultCpp);
-
- if(test)
- object_is_gda_value = true;
-
- if(object_is_gda_value && G_IS_VALUE(&value))
- {
- valueResult = Gnome::Gda::Value(&value);
- //Make sure that the value is of the expected Gda type:
- //TODO_Performance:
- valueResult = Glom::Conversions::convert_value(valueResult, result_type);
- //std::cout << "DEBUG: glom_evaluate_python_function_implementation(): valueResult Gda type=" << g_type_name(valueResult.get_value_type()) << std::endl;
- g_value_unset(&value);
- }
- else
- {
- //g_warning("debug: pyResult is not a gda.value");
-
- //For instance, if one of the fields was empty, then the calculation might want to return an empty value,
- //instead of returning 0.
- if(pyResultCpp == boost::python::object()) //Check if it is PyNone
- {
- //The result should be an appropriate empty value for this field type:
- valueResult = Conversions::get_empty_value(result_type);
- //std::cout << "DEBUG: glom_evaluate_python_function_implementation(): empty value Gda type=" << g_type_name(valueResult.get_value_type()) << std::endl;
- }
- else
- {
- //TODO: Handle numeric/date/time types:
- //(though I don't think this code is ever reached. murrayc)
-
- //Treat this as a string or something that can be converted to a string:
- const char* pchResult = 0;
- try
- {
- pchResult = boost::python::extract<const char*>(pyResultCpp);
- }
- catch(const boost::python::error_already_set& ex)
- {
- std::cerr << "Glom: Exception caught from boost::python::extract() while converting result to a const char*." << std::endl << func_name << std::endl;
- ShowTrace();
- return valueResult;
- }
-
- if(pchResult)
- {
- bool success = false;
- valueResult = Conversions::parse_value(result_type, pchResult, success, true /* iso_format */);
- std::cout << "DEBUG: glom_evaluate_python_function_implementation(): parsed value Gda type=" << g_type_name(valueResult.get_value_type()) << std::endl;
- }
- else
- HandlePythonError();
- }
- }
- }
+ HandlePythonError();
}
}
-
- Py_FlushLine();
- PyErr_Clear();
-
-
- //We did this in main(): Py_Finalize();
-
+
return valueResult;
}
-/*
-
-examples:
-
- return record.fields["name_first"] + " " + record.fields["name_last"]
-
- return record.related_records["contacts"][0].fields["name_first"]
-
- return record.related_records["invoice lines"].sum("cost") )
-*/
} //namespace Glom
diff --git a/glom/python_embed/glom_python.h b/glom/python_embed/glom_python.h
index 525b68c..f45abb4 100644
--- a/glom/python_embed/glom_python.h
+++ b/glom/python_embed/glom_python.h
@@ -23,6 +23,7 @@
#include <libglom/data_structure/field.h>
#include <libglom/document/document.h>
+#include <libglom/python_embed/py_glom_ui.h>
#include <glibmm/ustring.h>
namespace Glom
@@ -41,7 +42,8 @@ bool gda_python_module_is_available();
typedef std::map<Glib::ustring, Gnome::Gda::Value> type_map_fields;
/** Run a script, ignoring the python return value.
- * The record object will be writable.
+ * The record object will be writable and the function will receive a ui
+ * parameter so it can control navigation in the UI.
*/
void glom_execute_python_function_implementation(const Glib::ustring& func_impl,
const type_map_fields& field_values,
@@ -49,10 +51,12 @@ void glom_execute_python_function_implementation(const Glib::ustring& func_impl,
const Glib::ustring& table_name,
const sharedptr<const Field>& key_field,
const Gnome::Gda::Value& key_field_value,
- const Glib::RefPtr<Gnome::Gda::Connection>& opened_connection);
+ const Glib::RefPtr<Gnome::Gda::Connection>& opened_connection,
+ const PythonUICallbacks& callbacks);
/** Run a python calculation, returning the python return value.
- * The record object will be read only unless @a read_only=false.
+ * @param for_script: If this is true then the record object will be writable,
+ * and the function will receive a ui parameter so it can control navigation in the UI.
*/
Gnome::Gda::Value glom_evaluate_python_function_implementation(Field::glom_field_type result_type,
const Glib::ustring& func_impl,
@@ -61,8 +65,7 @@ Gnome::Gda::Value glom_evaluate_python_function_implementation(Field::glom_field
const Glib::ustring& table_name,
const sharedptr<const Field>& key_field,
const Gnome::Gda::Value& key_field_value,
- const Glib::RefPtr<Gnome::Gda::Connection>& opened_connection,
- bool read_only = true);
+ const Glib::RefPtr<Gnome::Gda::Connection>& opened_connection);
} //namespace Glom
diff --git a/glom/python_embed/python_module/py_glom_module.cc b/glom/python_embed/python_module/py_glom_module.cc
index 155d717..32c08af 100644
--- a/glom/python_embed/python_module/py_glom_module.cc
+++ b/glom/python_embed/python_module/py_glom_module.cc
@@ -27,6 +27,7 @@
#include <libglom/python_embed/py_glom_record.h>
#include <libglom/python_embed/py_glom_related.h>
#include <libglom/python_embed/py_glom_relatedrecord.h>
+#include <libglom/python_embed/py_glom_ui.h>
using namespace Glom;
@@ -55,4 +56,9 @@ BOOST_PYTHON_MODULE(glom_1_14)
.def("__getitem__", &PyGlomRelatedRecord::getitem)
.def("__len__", &PyGlomRelatedRecord::len)
;
+
+ boost::python::class_<PyGlomUI>("UI")
+ .def("show_table_details", &PyGlomUI::show_table_details)
+ .def("show_table_list", &PyGlomUI::show_table_list)
+ ;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]