[glom] Python button scripts: Rename print() to print_layout() and add start_new_record().



commit 82b7eba8c0766f0c9893c78a039e55761906a1cd
Author: Murray Cumming <murrayc murrayc com>
Date:   Mon Mar 8 17:17:57 2010 +0100

    Python button scripts: Rename print() to print_layout() and add start_new_record().
    
    * glom/application.[h|cc]
    * glom/frame_glom.[h|cc]
    * glom/libglom/python_embed/py_glom_ui.[h|cc]
    * glom/mode_data/box_data.[h|cc]
    * glom/mode_data/box_data_details.[h|cc]
    * glom/mode_data/notebook_data.[h|cc]
    * glom/python_embed/python_module/py_glom_module.cc:
    * tests/test_python_execute_script.cc:
        Add a ui.start_new_record() python method, and rename ui.print() to
        ui.print_layout() because print seems to be a python keyword that can't
        be used as a method name, seen when trying to use it in the unit test.

 ChangeLog                                         |   16 +++
 glom/application.cc                               |    6 +-
 glom/application.h                                |    6 +-
 glom/frame_glom.cc                                |  139 ++++++++++-----------
 glom/frame_glom.h                                 |   26 ++--
 glom/libglom/python_embed/py_glom_ui.cc           |   12 ++-
 glom/libglom/python_embed/py_glom_ui.h            |   16 ++-
 glom/mode_data/box_data.cc                        |   17 ++-
 glom/mode_data/box_data.h                         |    6 +-
 glom/mode_data/box_data_details.cc                |   60 +++++-----
 glom/mode_data/box_data_details.h                 |   16 +--
 glom/mode_data/notebook_data.cc                   |   44 +++----
 glom/mode_data/notebook_data.h                    |   20 ++--
 glom/python_embed/python_module/py_glom_module.cc |    3 +-
 tests/test_python_execute_script.cc               |   55 +++++++--
 15 files changed, 257 insertions(+), 185 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index da003f2..6301198 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,19 @@
+2010-03-08  Murray Cumming  <murrayc murrayc-desktop>
+
+    Python button scripts: Rename print() to print_layout() and add start_new_record().
+
+	* glom/application.[h|cc]
+	* glom/frame_glom.[h|cc]
+	* glom/libglom/python_embed/py_glom_ui.[h|cc]
+	* glom/mode_data/box_data.[h|cc]
+	* glom/mode_data/box_data_details.[h|cc]
+	* glom/mode_data/notebook_data.[h|cc]
+	* glom/python_embed/python_module/py_glom_module.cc:
+	* tests/test_python_execute_script.cc:
+    Add a ui.start_new_record() python method, and rename ui.print() to
+    ui.print_layout() because print seems to be a python keyword that can't
+    be used as a method name, seen when trying to use it in the unit test.
+
 2010-03-08  Peter Penz  <ppenz openismus com>
 
 	Fix the build with exceptions disabled.
diff --git a/glom/application.cc b/glom/application.cc
index 4b63a6d..56b5370 100644
--- a/glom/application.cc
+++ b/glom/application.cc
@@ -2564,7 +2564,7 @@ void Application::print_report(const Glib::ustring& report_name)
   m_pFrame->on_menu_report_selected(report_name);
 }
 
-void Application::print()
+void Application::print_layout()
 {
   if(!m_pFrame)
     return;
@@ -2572,7 +2572,11 @@ void Application::print()
   m_pFrame->on_menu_file_print();
 }
 
+void Application::start_new_record()
+{
+  m_pFrame->on_menu_add_record();
 
+}
 
 
 } //namespace Glom
diff --git a/glom/application.h b/glom/application.h
index 65dc785..3457b34 100644
--- a/glom/application.h
+++ b/glom/application.h
@@ -115,7 +115,11 @@ public:
 
   /** Print the current layout for the current table.
    */
-  void print();
+  void print_layout();
+
+  /** Offer the user the UI to add a new record,
+   */
+  void start_new_record();
 
   static Application* get_application();
 
diff --git a/glom/frame_glom.cc b/glom/frame_glom.cc
index 701d11a..2c483c9 100644
--- a/glom/frame_glom.cc
+++ b/glom/frame_glom.cc
@@ -121,7 +121,7 @@ Frame_Glom::Frame_Glom(BaseObjectType* cobject, const Glib::RefPtr<Gtk::Builder>
   builder->get_widget("hbox_footer", m_box_footer);
   builder->get_widget("label_mode", m_pLabel_Mode);
   builder->get_widget("label_user_level", m_pLabel_userlevel);
-  
+
   //Hide unnecessary widgets on maemo that take too much space,
   //and reduce the border width:
   #ifdef GLOM_ENABLE_MAEMO
@@ -135,7 +135,7 @@ Frame_Glom::Frame_Glom(BaseObjectType* cobject, const Glib::RefPtr<Gtk::Builder>
   m_pBox_QuickFind = Gtk::manage(new Gtk::HBox(false, Utils::DEFAULT_SPACING_SMALL));
   Gtk::Label* label = Gtk::manage(new Gtk::Label(_("Quick Find")));
   m_pBox_QuickFind->pack_start(*label, Gtk::PACK_SHRINK);
-  
+
   #ifndef GLOM_ENABLE_MAEMO
   m_pEntry_QuickFind = Gtk::manage(new Gtk::Entry());
   #else
@@ -148,13 +148,13 @@ Frame_Glom::Frame_Glom(BaseObjectType* cobject, const Glib::RefPtr<Gtk::Builder>
   #ifndef GLOM_ENABLE_MAEMO
   m_pButton_QuickFind = Gtk::manage(new Gtk::Button(_("_Find"), true));
   #else
-  m_pButton_QuickFind = Gtk::manage(new Hildon::Button(Gtk::Hildon::SIZE_AUTO, 
+  m_pButton_QuickFind = Gtk::manage(new Hildon::Button(Gtk::Hildon::SIZE_AUTO,
     Hildon::BUTTON_ARRANGEMENT_VERTICAL, _("Find"), _("Search for records")));
   #endif
   m_pButton_QuickFind->signal_clicked().connect(
     sigc::mem_fun(*this, &Frame_Glom::on_button_quickfind) );
   m_pBox_QuickFind->pack_start(*m_pButton_QuickFind, Gtk::PACK_SHRINK);
-  
+
   m_pBox_QuickFind->show_all_children();
   m_pBox_QuickFind->hide();
 
@@ -190,10 +190,10 @@ Frame_Glom::Frame_Glom(BaseObjectType* cobject, const Glib::RefPtr<Gtk::Builder>
   add_view(&m_Notebook_Find); //Also a composite view.
 
   on_userlevel_changed(AppState::USERLEVEL_OPERATOR); //A default to show before a document is created or loaded.
-  
+
   #ifdef GLOM_ENABLE_MAEMO
   m_maemo_window_find.set_title(_("Glom: Find"));
-  
+
   Gtk::VBox* vbox = Gtk::manage(new Gtk::VBox(false, Utils::DEFAULT_SPACING_SMALL));
   vbox->pack_start(*m_pBox_QuickFind, Gtk::PACK_SHRINK);
   vbox->pack_start(m_Notebook_Find, Gtk::PACK_EXPAND_WIDGET);
@@ -225,14 +225,14 @@ Frame_Glom::~Frame_Glom()
     delete m_pDialogConnection;
     m_pDialogConnection = 0;
   }
-  
-  
+
+
   if(m_dialog_progess_connection_startup)
   {
     delete m_dialog_progess_connection_startup;
     m_dialog_progess_connection_startup = 0;
   }
-  
+
   if(m_dialog_progess_connection_cleanup)
   {
     delete m_dialog_progess_connection_cleanup;
@@ -441,14 +441,14 @@ void Frame_Glom::show_table_allow_empty(const Glib::ustring& table_name, const G
       //Start with the last-used found set (sort order and where clause)
       //for this layout:
       //(This would be ignored anyway if a details primary key is specified.)
-      Document* document = get_document(); 
+      Document* document = get_document();
       if(document)
         found_set = document->get_criteria_current(m_table_name);
 
       //Make sure that this is set:
       found_set.m_table_name = m_table_name;
 
-      //If there is no saved sort clause, 
+      //If there is no saved sort clause,
       //then sort by the ID, just so we sort by something, so that the order is predictable:
       if(found_set.m_sort_clause.empty())
       {
@@ -460,10 +460,10 @@ void Frame_Glom::show_table_allow_empty(const Glib::ustring& table_name, const G
 
           found_set.m_sort_clause.clear();
 
-          //Avoid the sort clause if the found set will include too many records, 
+          //Avoid the sort clause if the found set will include too many records,
           //because that would be too slow.
           //The user can explicitly request a sort later, by clicking on a column header.
-          //TODO_Performance: This causes an almost-duplicate COUNT query (we do it in the treemodel too), but it's not that slow. 
+          //TODO_Performance: This causes an almost-duplicate COUNT query (we do it in the treemodel too), but it's not that slow.
           sharedptr<LayoutItem_Field> layout_item_temp = sharedptr<LayoutItem_Field>::create();
           layout_item_temp->set_full_field_details(field_primary_key);
           type_vecLayoutFields layout_fields;
@@ -590,7 +590,7 @@ void Frame_Glom::on_menu_userlevel_Developer(const Glib::RefPtr<Gtk::RadioAction
         const int response = dialog.run();
         test = (response == Gtk::RESPONSE_OK);
       }
-      
+
       if(!test)
       {
         //Abort the change of user level:
@@ -787,7 +787,7 @@ void Frame_Glom::export_data_to_stream(std::ostream& the_stream, const FoundSet&
   }
 
   const Glib::ustring query = Utils::build_sql_select_with_where_clause(found_set.m_table_name, fieldsSequence, found_set.m_where_clause, found_set.m_extra_join, found_set.m_sort_clause, found_set.m_extra_group_by);
- 
+
   //TODO: Lock the database (prevent changes) during export.
   Glib::RefPtr<Gnome::Gda::DataModel> result = query_execute_select(query);
 
@@ -825,7 +825,7 @@ void Frame_Glom::export_data_to_stream(std::ostream& the_stream, const FoundSet&
 
             if(layout_item->get_glom_type() == Field::TYPE_IMAGE) //This is too much data.
             {
-              // Some extra debug checks, 
+              // Some extra debug checks,
               // though we believe that all these problems are now fixed in File::to_file_format():
 
               const char* newline_to_find = "\r\n";
@@ -844,16 +844,16 @@ void Frame_Glom::export_data_to_stream(std::ostream& the_stream, const FoundSet&
                 continue;
               }
             }
-            
+
             if(layout_item->get_glom_type() == Field::TYPE_TEXT)
             {
               //The CSV RFC says text may be quoted and should be if it has newlines:
-              row_string += ("\"" + field_text + "\""); 
+              row_string += ("\"" + field_text + "\"");
             }
             else
               row_string += field_text;
 
-           
+
             //std::cout << "  field name=" << layout_item->get_name() << ", value=" << layout_item->m_field.sql(value) << std::endl;
           //}
         }
@@ -993,11 +993,11 @@ void Frame_Glom::on_menu_file_toggle_share(const Glib::RefPtr<Gtk::ToggleAction>
         bool added = false;
         if(initial_password_provided)
           added = add_user(user, password, GLOM_STANDARD_GROUP_NAME_DEVELOPER);
-        
+
         if(initial_password_provided && added)
         {
           //Use the new user/password from now on:
-          ConnectionPool* connectionpool = ConnectionPool::get_instance();      
+          ConnectionPool* connectionpool = ConnectionPool::get_instance();
           connectionpool->set_user(user);
           connectionpool->set_password(password);
         }
@@ -1009,7 +1009,7 @@ void Frame_Glom::on_menu_file_toggle_share(const Glib::RefPtr<Gtk::ToggleAction>
       }
       else
       {
-        //Ask for the password of a developer user, to 
+        //Ask for the password of a developer user, to
         //a) Check that the user knows it, so he won't lose access.
         //b) Reconnect as that user so we can remove the default user.
         //TODO: Check that this user is a developer.
@@ -1025,15 +1025,15 @@ void Frame_Glom::on_menu_file_toggle_share(const Glib::RefPtr<Gtk::ToggleAction>
       if(change) //If nothing has gone wrong so far.
       {
         //Remove the default no-password user, because that would be a security hole:
-        //We do this after adding/using the non-default user, because we can't 
+        //We do this after adding/using the non-default user, because we can't
         //remove a currently-used user.
         const bool default_user_exists = Privs::get_default_developer_user_exists();
         if(default_user_exists)
         {
           //Force a reconnection with the new password:
-          //ConnectionPool* connectionpool = ConnectionPool::get_instance();      
+          //ConnectionPool* connectionpool = ConnectionPool::get_instance();
 
-          //Remove it, after stopping it from being the database owner: 
+          //Remove it, after stopping it from being the database owner:
           bool disabled = true;
           Glib::ustring default_password;
           const Glib::ustring default_user = Privs::get_default_developer_user_name(default_password);
@@ -1120,7 +1120,7 @@ void Frame_Glom::on_menu_file_toggle_share(const Glib::RefPtr<Gtk::ToggleAction>
     {
       sharedconnection->close();
       sharedconnection.clear();
-    }	
+    }
 
     connectionpool->cleanup( sigc::mem_fun(*this, &Frame_Glom::on_connection_cleanup_progress) );
 
@@ -1178,7 +1178,7 @@ void Frame_Glom::on_menu_Mode_Data()
 
 void Frame_Glom::on_menu_Mode_Find()
 {
-  //This can take quite a long time, flicking between 1 or 2 intermediate screens. 
+  //This can take quite a long time, flicking between 1 or 2 intermediate screens.
   //It shouldn't, but until we fix that, let's show the busy cursor while it's working:
   BusyCursor busy_cursor(get_app_window());
 
@@ -1194,7 +1194,7 @@ void Frame_Glom::on_menu_Mode_Find()
 
   if(!set_mode(MODE_Find))
     return;
-  
+
   show_table(m_table_name);
 
   if(previously_in_data_mode)
@@ -1202,26 +1202,24 @@ void Frame_Glom::on_menu_Mode_Find()
     //Show the same layout in Find mode as was just being viewed in Data mode:
     m_Notebook_Find.set_current_view(list_or_details);
   }
-  
+
   #ifdef GLOM_ENABLE_CLIENT_ONLY
   Gtk::Window* parent = get_app_window();
   g_assert(parent);
   if(parent)
     m_maemo_window_find.set_transient_for(*parent);
-    
+
   m_maemo_window_find.show(); //TODO: Switch back to data on hide?
   #endif
 }
 
-#ifdef GLOM_ENABLE_MAEMO
 void Frame_Glom::on_menu_add_record()
 {
   BusyCursor busy_cursor(get_app_window());
-  
+
   //Note: This should only be called in Data mode.
   m_Notebook_Data.do_menu_file_add_record();
 }
-#endif //GLOM_ENABLE_MAEMO
 
 
 #ifndef GLOM_ENABLE_CLIENT_ONLY
@@ -1237,7 +1235,7 @@ void Frame_Glom::on_menu_File_EditPrintLayouts()
 
 void Frame_Glom::on_menu_Tables_EditTables()
 {
-  do_menu_Navigate_Table(); 
+  do_menu_Navigate_Table();
 }
 
 void Frame_Glom::on_menu_Tables_AddRelatedTable()
@@ -1334,8 +1332,8 @@ void Frame_Glom::on_dialog_add_related_table_response(int response)
         std::cerr << "Frame_Glom::on_menu_Tables_AddRelatedTable(): create_table_with_default_fields() failed." << std::endl;
         return;
       }
-   
-      //Create the new relationship: 
+
+      //Create the new relationship:
       sharedptr<Relationship> relationship = sharedptr<Relationship>::create();
 
       relationship->set_name(relationship_name);
@@ -1380,7 +1378,7 @@ void Frame_Glom::on_dialog_add_related_table_request_edit_fields()
 
 void Frame_Glom::do_menu_Navigate_Table(bool open_default)
 {
-  
+
   if(get_document()->get_connection_database().empty())
   {
     alert_no_table();
@@ -1390,7 +1388,7 @@ void Frame_Glom::do_menu_Navigate_Table(bool open_default)
   Glib::ustring default_table_name;
   if(open_default)
     default_table_name = get_document()->get_default_table();
-  
+
 #ifndef GLOM_ENABLE_MAEMO
   //Create the dialog, if it has not already been created:
   if(!m_pBox_Tables)
@@ -1504,7 +1502,7 @@ void Frame_Glom::on_notebook_find_criteria(const Glib::ustring& where_clause)
   {
     bool records_found = false;
 
-    { //Extra scope, to control the lifetime of the busy cursor. 
+    { //Extra scope, to control the lifetime of the busy cursor.
       BusyCursor busy_cursor(pApp);
 
       pApp->set_mode_data();
@@ -1546,8 +1544,8 @@ void Frame_Glom::on_userlevel_changed(AppState::userlevels userlevel)
 
   if(m_pLabel_userlevel)
     m_pLabel_userlevel->set_text(user_level_name);
-  
-  show_table_title(); 
+
+  show_table_title();
 }
 
 void Frame_Glom::show_table_title()
@@ -1567,7 +1565,7 @@ void Frame_Glom::show_table_title()
     table_label = m_table_name;
 
 #ifdef GLOM_ENABLE_MAEMO
-  //Show the system's human-readable title and the table title in 
+  //Show the system's human-readable title and the table title in
   //the window's title bar:
   Gtk::Window* app = get_app_window();
   if(app)
@@ -1630,8 +1628,8 @@ void Frame_Glom::update_table_in_document_from_database()
               //Update the field information:
 
               // Ignore things that libgda does not report from the database properly:
-              // We do this also in Field::field_info_from_database_is_equal() and 
-              // Base_DB::get_fields_for_table(), 
+              // We do this also in Field::field_info_from_database_is_equal() and
+              // Base_DB::get_fields_for_table(),
               // so make sure that we ignore the same things everywhere always
               // TODO: Avoid that duplication?
               field_info_db->set_auto_increment( field_document->get_auto_increment() );
@@ -1882,7 +1880,7 @@ void Frame_Glom::on_menu_developer_reports()
     alert_no_table(); //TODO: Disable the menu item instead.
     return;
   }
-  
+
   //Create the widget if necessary:
   if(!m_pBox_Reports)
   {
@@ -1927,7 +1925,7 @@ void Frame_Glom::on_menu_developer_print_layouts()
 
     m_pBox_PrintLayouts->signal_selected.connect(sigc::mem_fun(*this, &Frame_Glom::on_box_print_layouts_selected));
   }
-  
+
   m_pBox_PrintLayouts->init_db_details(m_table_name);
   m_pDialog_PrintLayouts->show();
 }
@@ -1997,7 +1995,7 @@ void Frame_Glom::on_developer_dialog_hide()
 }
 #endif // !GLOM_ENABLE_CLIENT_ONLY
 
-namespace 
+namespace
 {
   void setup_connection_pool_from_document(Document* document)
   {
@@ -2057,7 +2055,7 @@ void Frame_Glom::on_connection_initialize_progress()
 {
   if(!m_dialog_progess_connection_initialize)
     m_dialog_progess_connection_initialize = Utils::get_and_show_pulse_dialog(_("Initializing Database Data"), get_app_window());
-        
+
   m_dialog_progess_connection_initialize->pulse();
 }
 #endif //GLOM_ENABLE_CLIENT_ONLY
@@ -2066,7 +2064,7 @@ void Frame_Glom::on_connection_startup_progress()
 {
   if(!m_dialog_progess_connection_startup)
     m_dialog_progess_connection_startup = Utils::get_and_show_pulse_dialog(_("Starting Database Server"), get_app_window());
-        
+
   m_dialog_progess_connection_startup->pulse();
 }
 
@@ -2074,7 +2072,7 @@ void Frame_Glom::on_connection_cleanup_progress()
 {
   if(!m_dialog_progess_connection_cleanup)
     m_dialog_progess_connection_cleanup = Utils::get_and_show_pulse_dialog(_("Stopping Database Server"), get_app_window());
-        
+
   m_dialog_progess_connection_cleanup->pulse();
 }
 
@@ -2082,7 +2080,7 @@ bool Frame_Glom::handle_connection_initialize_errors(ConnectionPool::InitErrors
 {
   Glib::ustring title;
   Glib::ustring message;
-  
+
   if(error == ConnectionPool::Backend::INITERROR_NONE)
     return true;
   else if(error == ConnectionPool::Backend::INITERROR_DIRECTORY_ALREADY_EXISTS)
@@ -2100,9 +2098,9 @@ bool Frame_Glom::handle_connection_initialize_errors(ConnectionPool::InitErrors
     title = _("Could Not Start Database Server");
     message = _("There was an error when attempting to start the database server.");
   }
-  
+
   Utils::show_ok_dialog(title, message, *get_app_window(), Gtk::MESSAGE_ERROR);
-  
+
   return false;
 }
 
@@ -2217,14 +2215,14 @@ bool Frame_Glom::connection_request_password_and_choose_new_database_name()
         //Use the default user because we are not network shared:
         user = Privs::get_default_developer_user_name(password);
       }
- 
+
       // Create the requested self-hosting database:
-      
+
       //Set the connection details in the ConnectionPool singleton.
       //The ConnectionPool will now use these every time it tries to connect.
       connection_pool->set_user(user);
       connection_pool->set_password(password);
-      
+
       const bool initialized = handle_connection_initialize_errors( connection_pool->initialize(
         sigc::mem_fun(*this, &Frame_Glom::on_connection_initialize_progress) ) );
 
@@ -2252,7 +2250,7 @@ bool Frame_Glom::connection_request_password_and_choose_new_database_name()
       //Ask for connection details:
       m_pDialogConnection->load_from_document(); //Get good defaults.
       m_pDialogConnection->set_transient_for(*get_app_window());
- 
+
       const int response = Glom::Utils::dialog_run_with_help(m_pDialogConnection, "dialog_connection");
       m_pDialogConnection->hide();
 
@@ -2301,7 +2299,7 @@ bool Frame_Glom::connection_request_password_and_choose_new_database_name()
   // Do startup, such as starting the self-hosting database server
   if(!connection_pool->startup( sigc::mem_fun(*this, &Frame_Glom::on_connection_startup_progress) ))
     return false;
-    
+
   if(m_dialog_progess_connection_startup)
   {
     delete m_dialog_progess_connection_startup;
@@ -2367,7 +2365,7 @@ bool Frame_Glom::connection_request_password_and_choose_new_database_name()
       }
       else
       {
-        std::cout << "Frame_Glom::connection_request_password_and_choose_new_database_name(): unused database name successfully found: " << database_name_possible << std::endl; 
+        std::cout << "Frame_Glom::connection_request_password_and_choose_new_database_name(): unused database name successfully found: " << database_name_possible << std::endl;
         //The connection to the server is OK, but the specified database does not exist.
         //That's good - we were looking for an unused database name.
 
@@ -2411,14 +2409,14 @@ bool Frame_Glom::connection_request_password_and_choose_new_database_name()
   }
 
   cleanup_connection();
-  
+
   return false;
 }
 #endif //GLOM_ENABLE_CLIENT_ONLY
 
 void Frame_Glom::cleanup_connection()
 {
-  ConnectionPool* connection_pool = ConnectionPool::get_instance(); 
+  ConnectionPool* connection_pool = ConnectionPool::get_instance();
   connection_pool->cleanup( sigc::mem_fun(*this, &Frame_Glom::on_connection_cleanup_progress) );
 
   if(m_dialog_progess_connection_cleanup)
@@ -2473,7 +2471,7 @@ bool Frame_Glom::connection_request_password_and_attempt(bool& database_not_foun
   setup_connection_pool_from_document(document);
   if(!connection_pool->startup( sigc::mem_fun(*this, &Frame_Glom::on_connection_startup_progress) ))
     return false;
-    
+
   if(m_dialog_progess_connection_startup)
   {
     delete m_dialog_progess_connection_startup;
@@ -2494,7 +2492,7 @@ bool Frame_Glom::connection_request_password_and_attempt(bool& database_not_foun
 
     Utils::get_glade_widget_derived_with_warning("dialog_connection", m_pDialogConnection);
     add_view(m_pDialogConnection); //Also a composite view.
-  
+
     m_pDialogConnection->load_from_document(); //Get good defaults.
     m_pDialogConnection->set_transient_for(*get_app_window());
 
@@ -2516,7 +2514,7 @@ bool Frame_Glom::connection_request_password_and_attempt(bool& database_not_foun
   }
 
 
-  //Ask for connection details: 
+  //Ask for connection details:
   while(true) //Loop until a return
   {
     //Only show the dialog if we don't know the correct username/password yet:
@@ -2551,7 +2549,7 @@ bool Frame_Glom::connection_request_password_and_attempt(bool& database_not_foun
         }
         #else //GLIBMM_EXCEPTIONS_ENABLED
         std::auto_ptr<ExceptionConnection> local_error;
-        sharedconnection = 
+        sharedconnection =
           m_pDialogConnection->connect_to_server_with_connection_settings(local_error);
         if(!local_error.get())
           return true;
@@ -2565,7 +2563,7 @@ bool Frame_Glom::connection_request_password_and_attempt(bool& database_not_foun
         ConnectionPool* connectionpool = ConnectionPool::get_instance();
         connectionpool->set_user(known_username);
         connectionpool->set_password(known_password);
-    
+
         #ifdef GLIBMM_EXCEPTIONS_ENABLED
         try
         {
@@ -2761,14 +2759,14 @@ void Frame_Glom::on_menu_print_layout_selected(const Glib::ustring& print_layout
     //TODO: Use this when gtkmm and GTK+ have been fixed: page_setup = Gtk::PageSetup::create(key_file);
     page_setup = Glib::wrap(gtk_page_setup_new_from_key_file(key_file.gobj(), 0, 0));
   }
-  
+
   print->set_default_page_setup(page_setup);
-  
+
   //print->set_print_settings(m_refSettings);
 
   //print->signal_done().connect(sigc::bind(sigc::mem_fun(*this,
   //                &ExampleWindow::on_printoperation_done), print));
-  
+
   const FoundSet found_set = m_Notebook_Data.get_found_set_details();
   canvas.fill_with_data(found_set);
 
@@ -2865,7 +2863,7 @@ void Frame_Glom::on_dialog_tables_hide()
       //Select a different table if the current one no longer exists:
       if(!document->get_table_is_known(m_table_name))
       {
-        //Open the default table, or the first table if there is no default: 
+        //Open the default table, or the first table if there is no default:
         Glib::ustring table_name = document->get_default_table();
         if(table_name.empty())
           table_name = document->get_first_table();
@@ -2947,4 +2945,3 @@ Glib::ustring Frame_Glom::get_shown_table_name() const
 }
 
 } //namespace Glom
-
diff --git a/glom/frame_glom.h b/glom/frame_glom.h
index 26bec8c..94fec74 100644
--- a/glom/frame_glom.h
+++ b/glom/frame_glom.h
@@ -66,7 +66,7 @@ class Frame_Glom :
   //public GlomBakery::View_Composite<Document>,
   public Base_DB //Inherits from View_Composite.
 {
-public: 
+public:
   Frame_Glom(BaseObjectType* cobject, const Glib::RefPtr<Gtk::Builder>& builder);
   virtual ~Frame_Glom();
 
@@ -91,11 +91,11 @@ public:
 
   void on_menu_Mode_Data();
   void on_menu_Mode_Find();
-  
-  #ifdef GLOM_ENABLE_MAEMO
+
+  //TODO: Actually put this in the menu for non-maemo too? #ifdef GLOM_ENABLE_MAEMO
   void on_menu_add_record();
-  #endif
-  
+  //#endif
+
   void on_menu_report_selected(const Glib::ustring& report_name);
 
 #ifndef GLOM_ENABLE_CLIENT_ONLY
@@ -192,10 +192,10 @@ public:
    * @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:
 
-  
+
 
   //virtual void set_document(Document* pDocument); //override
 
@@ -253,7 +253,7 @@ private:
    * @result Whether to try again.
    */
   bool handle_request_password_connection_error(bool asked_for_password, const ExceptionConnection& ex, bool& database_not_found);
-  
+
   //Member data:
   Glib::ustring m_table_name;
 
@@ -278,22 +278,22 @@ private:
 #endif //GLOM_ENABLE_MAEMO
 
   Notebook_Data m_Notebook_Data;
-  
+
   Gtk::HBox* m_pBox_QuickFind; //Only show this when in Find mode.
   Gtk::Entry* m_pEntry_QuickFind;
   Gtk::Button* m_pButton_QuickFind;
   Notebook_Find m_Notebook_Find;
-  
+
   #ifdef GLOM_ENABLE_MAEMO
   Hildon::StackableWindow m_maemo_window_find;
   #endif
-  
+
 #ifndef GLOM_ENABLE_CLIENT_ONLY
   //Developer:
   Window_BoxHolder* m_pDialog_Reports;
   Dialog_Layout_Report* m_pDialogLayoutReport;
   Box_Reports* m_pBox_Reports;
-  
+
   Window_BoxHolder* m_pDialog_PrintLayouts;
   Window_PrintLayout_Edit* m_pDialogLayoutPrint;
   Box_Print_Layouts* m_pBox_PrintLayouts;
@@ -302,7 +302,7 @@ private:
   Dialog_Relationships* m_pDialog_Relationships;
   Dialog_AddRelatedTable* m_dialog_addrelatedtable;
   Dialog_RelationshipsOverview* m_dialog_relationships_overview;
-    
+
   Dialog_ProgressCreating* m_dialog_progess_connection_initialize;
 #endif //GLOM_ENABLE_CLIENT_ONLY
 
diff --git a/glom/libglom/python_embed/py_glom_ui.cc b/glom/libglom/python_embed/py_glom_ui.cc
index e536c4f..c71df58 100644
--- a/glom/libglom/python_embed/py_glom_ui.cc
+++ b/glom/libglom/python_embed/py_glom_ui.cc
@@ -60,10 +60,10 @@ void PyGlomUI::show_table_list(const std::string& table_name)
     m_callbacks->m_slot_show_table_list(table_name);
 }
 
-void PyGlomUI::print()
+void PyGlomUI::print_layout()
 {
-  if(m_callbacks && m_callbacks->m_slot_print)
-    m_callbacks->m_slot_print();
+  if(m_callbacks && m_callbacks->m_slot_print_layout)
+    m_callbacks->m_slot_print_layout();
 }
 
 
@@ -73,5 +73,11 @@ void PyGlomUI::print_report(const std::string& report_name)
     m_callbacks->m_slot_print_report(report_name);
 }
 
+void PyGlomUI::start_new_record()
+{
+  if(m_callbacks && m_callbacks->m_slot_print_report)
+    m_callbacks->m_slot_start_new_record();
+}
+
 
 } //namespace Glom
diff --git a/glom/libglom/python_embed/py_glom_ui.h b/glom/libglom/python_embed/py_glom_ui.h
index 4c727d6..22a7384 100644
--- a/glom/libglom/python_embed/py_glom_ui.h
+++ b/glom/libglom/python_embed/py_glom_ui.h
@@ -52,9 +52,15 @@ public:
   sigc::slot<void, const Glib::ustring&> m_slot_print_report;
 
    /** For example,
-   * void on_print();
+   * void on_print_layout();
    */
-  sigc::slot<void> m_slot_print;
+  sigc::slot<void> m_slot_print_layout;
+
+  /** For example,
+   * void on_start_new_record(const Gnome::Gda::Value& new_primary_key_value);
+   * Use an empty Value for auto-created fields.
+   */
+  sigc::slot<void> m_slot_start_new_record;
 };
 
 class PyGlomUI
@@ -75,12 +81,16 @@ public:
 
   /** Print the current view of the current table.
    */
-  void print();
+  void print_layout();
 
   /** Print the named report from the current table.
    */
   void print_report(const std::string& report_name);
 
+  /** Offer the user the UI to add a new record.
+   */
+  void start_new_record();
+
 private:
   const PythonUICallbacks* m_callbacks;
 };
diff --git a/glom/mode_data/box_data.cc b/glom/mode_data/box_data.cc
index 1cc3f58..224cdea 100644
--- a/glom/mode_data/box_data.cc
+++ b/glom/mode_data/box_data.cc
@@ -374,11 +374,18 @@ void Box_Data::on_python_requested_print_report(const Glib::ustring& report_name
     app->print_report(report_name);
 }
 
-void Box_Data::on_python_requested_print()
+void Box_Data::on_python_requested_print_layout()
 {
   Application* app = Application::get_application();
   if(app)
-    app->print();
+    app->print_layout();
+}
+
+void Box_Data::on_python_requested_start_new_record()
+{
+  Application* app = Application::get_application();
+  if(app)
+    app->start_new_record();
 }
 
 
@@ -403,10 +410,12 @@ void Box_Data::execute_button_script(const sharedptr<const LayoutItem_Button>& l
       sigc::mem_fun(*this, &Box_Data::on_python_requested_show_table_details);
     callbacks.m_slot_show_table_list =
       sigc::mem_fun(*this, &Box_Data::on_python_requested_show_table_list);
-    callbacks.m_slot_print =
-      sigc::mem_fun(*this, &Box_Data::on_python_requested_print);
+    callbacks.m_slot_print_layout =
+      sigc::mem_fun(*this, &Box_Data::on_python_requested_print_layout);
     callbacks.m_slot_print_report =
       sigc::mem_fun(*this, &Box_Data::on_python_requested_print_report);
+    callbacks.m_slot_start_new_record =
+      sigc::mem_fun(*this, &Box_Data::on_python_requested_start_new_record);
 
     glom_execute_python_function_implementation(layout_item->get_script(),
       field_values, //TODO: Maybe use the field's type here.
diff --git a/glom/mode_data/box_data.h b/glom/mode_data/box_data.h
index c6da51f..6168929 100644
--- a/glom/mode_data/box_data.h
+++ b/glom/mode_data/box_data.h
@@ -111,13 +111,15 @@ protected:
   //Signal handlers:
   virtual void on_Button_Find(); //only used by _Find sub-classes. Should be MI.
 
+private:
   //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);
   void on_python_requested_print_report(const Glib::ustring& report_name);
-  void on_python_requested_print();
-
+  void on_python_requested_print_layout();
+  void on_python_requested_start_new_record();
 
+protected:
   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_data/box_data_details.cc b/glom/mode_data/box_data_details.cc
index 43061c5..89503f1 100644
--- a/glom/mode_data/box_data_details.cc
+++ b/glom/mode_data/box_data_details.cc
@@ -66,20 +66,20 @@ Box_Data_Details::Box_Data_Details(bool bWithNavButtons /* = true */)
   m_FlowTable.set_row_padding(0); //The hildon buttons and entries have their own default padding.
   m_FlowTable.set_column_padding(HILDON_MARGIN_DOUBLE); //As per the UI specs.
   #endif
-  
+
   //m_strHint = _("When you change the data in a field the database is updated immediately.\n Click [New] to add a new record.\n Leave automatic ID fields empty - they will be filled for you.");
 
 
   //m_ScrolledWindow.set_border_width(Utils::DEFAULT_SPACING_SMALL);
 #ifdef GLOM_ENABLE_MAEMO
-  // Allow horizontal scrolling in maemo because the screen is rather small and 
-  // there might be some database UIs that don't fit horizontally. Such a UI may 
+  // Allow horizontal scrolling in maemo because the screen is rather small and
+  // there might be some database UIs that don't fit horizontally. Such a UI may
   // be considered non-maemo-friendly, but it can still be fully viewed this way.
   // TODO: Prevent the need for horizontal scrolling.
   m_ScrolledWindow.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
 #else
   // Allow vertical scrolling, but never scroll horizontally:
-  m_ScrolledWindow.set_policy(Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC); 
+  m_ScrolledWindow.set_policy(Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
 #endif
   m_ScrolledWindow.set_shadow_type(Gtk::SHADOW_NONE); //SHADOW_IN is Recommended by the GNOME HIG, but looks odd.
 
@@ -176,7 +176,7 @@ void Box_Data_Details::set_found_set_from_primary_key_value()
   if(!m_primary_key_value.is_null())
   {
     //TODO: Use a SQL parameter instead of using sql().
-    m_found_set.m_where_clause = "\"" + m_table_name + "\".\"" + m_field_primary_key->get_name() + 
+    m_found_set.m_where_clause = "\"" + m_table_name + "\".\"" + m_field_primary_key->get_name() +
       "\" = " + m_field_primary_key->sql(m_primary_key_value);
     //std::cout << "  DEBUG: Box_Data_Details::set_primary_key_value(): m_found_set.m_where_clause = " << m_found_set.m_where_clause << std::endl;
   }
@@ -188,13 +188,13 @@ bool Box_Data_Details::init_db_details(const FoundSet& found_set, const Glib::us
 
   m_primary_key_value = primary_key_value;
   m_field_primary_key = get_field_primary_key_for_table(found_set.m_table_name);
-   
+
   const bool result = Box_Data::init_db_details(found_set, layout_platform); //Calls create_layout(), then fill_from_database()
 
   //This is not used much, but we create it anyway:
   m_found_set = found_set; //Not used much.
   set_found_set_from_primary_key_value();
- 
+
   return result;
 }
 
@@ -231,7 +231,7 @@ void Box_Data_Details::create_layout()
     {
       m_FlowTable.add_layout_group(*iter);
     }
-    
+
     m_FlowTable.align_child_group_labels();
   }
 
@@ -263,7 +263,7 @@ bool Box_Data_Details::fill_from_database()
     return false;
   }
 
-  //TODO: This should keep the connection open, so we don't need to 
+  //TODO: This should keep the connection open, so we don't need to
   //reconnect many times..
   sharedptr<SharedConnection> sharedconnection;
 
@@ -316,7 +316,7 @@ bool Box_Data_Details::fill_from_database()
         //Add extra possibly-non-visible columns that we need:
         sharedptr<LayoutItem_Field> layout_item = sharedptr<LayoutItem_Field>::create();
         layout_item->set_full_field_details(m_field_primary_key);
-        
+
         //Get the primary key index, adding the primary key if necessary:
         //TODO_Performance: Do this for create_layout() only, instead of repeating it for each refresh?:
         int index_primary_key = -1; //Arbitrary default.
@@ -337,10 +337,10 @@ bool Box_Data_Details::fill_from_database()
             sharedptr<const LayoutItem_Field> element = fieldsToGet[i];
             if(!element)
               continue;
-            
+
             if(element->get_name() != layout_item->get_name())
               continue;
-            
+
             //Compare the relationship and related relationship:
             sharedptr<const UsesRelationship> uses_a = layout_item;
             sharedptr<const UsesRelationship> uses_b = element;
@@ -378,14 +378,14 @@ bool Box_Data_Details::fill_from_database()
             {
               if(index_primary_key < cols_count)
               {
-#ifdef GLIBMM_EXCEPTIONS_ENABLED              
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
                 m_primary_key_value = result->get_value_at(index_primary_key, row_number);
 #else
               {
                 std::auto_ptr<Glib::Error> value_error;
                 m_primary_key_value = result->get_value_at(index_primary_key, row_number, value_error);
               }
-#endif 
+#endif
                 set_found_set_from_primary_key_value();
               }
             }
@@ -399,14 +399,14 @@ bool Box_Data_Details::fill_from_database()
               Gnome::Gda::Value value;
 
               if(!primary_key_is_empty)
-#ifdef GLIBMM_EXCEPTIONS_ENABLED              
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
                 value = result->get_value_at(i, row_number);
 #else
               {
                 std::auto_ptr<Glib::Error> value_error;
                 value = result->get_value_at(i, row_number, value_error);
               }
-#endif               
+#endif
               else
               {
                 value = Conversions::get_empty_value(layout_item->get_glom_type());
@@ -484,7 +484,7 @@ void Box_Data_Details::on_button_del()
     if(confirm_delete_record())
     {
       const bool bTest = record_delete(m_primary_key_value);
-  
+
       if(bTest)
       {
         //Tell the list that it has been deleted:
@@ -599,7 +599,7 @@ void Box_Data_Details::on_related_record_added(Gnome::Gda::Value /* strKeyValue
   }
   */
 
-  
+
 
   //Restore value:
   m_bDoNotRefreshRelated = bDoNotRefreshRelated;
@@ -628,7 +628,7 @@ Box_Data_Details::type_signal_void Box_Data_Details::signal_nav_last()
 
 Box_Data_Details::type_signal_record_deleted Box_Data_Details::signal_record_deleted()
 {
-  return m_signal_record_deleted; 
+  return m_signal_record_deleted;
 }
 #endif //GLOM_ENABLE_MAEMO
 
@@ -657,8 +657,8 @@ void Box_Data_Details::on_flowtable_layout_changed()
   Document* document = get_document();
   if(document)
     document->set_modified();
-    
-    
+
+
   //And fill it with data:
   fill_from_database();
 }
@@ -682,7 +682,7 @@ void Box_Data_Details::on_flowtable_field_open_details_requested(const sharedptr
   if(Conversions::value_is_empty(field_value))
     return; //Ignore empty ID fields.
 
-  //If it's a simple field that is part of a relationship, 
+  //If it's a simple field that is part of a relationship,
   //identifying a related record.
   sharedptr<const Relationship> relationship = get_document()->get_field_used_in_relationship_to_one(m_table_name, layout_field);
   if(relationship)
@@ -694,12 +694,12 @@ void Box_Data_Details::on_flowtable_field_open_details_requested(const sharedptr
   //If it is a related field that is a primary key,
   //meaning it identifies a record in another table:
   sharedptr<const Field> field_info = layout_field->get_full_field_details();
-  const bool field_is_related_primary_key = 
-    layout_field->get_has_relationship_name() && 
+  const bool field_is_related_primary_key =
+    layout_field->get_has_relationship_name() &&
     field_info && field_info->get_primary_key();
   if(field_is_related_primary_key)
   {
-    signal_requested_related_details().emit(layout_field->get_table_used(m_table_name), field_value);   
+    signal_requested_related_details().emit(layout_field->get_table_used(m_table_name), field_value);
   }
 }
 
@@ -730,7 +730,7 @@ void Box_Data_Details::on_flowtable_script_button_clicked(const sharedptr<const
     }
   }
 }
-     
+
 void Box_Data_Details::on_flowtable_field_edited(const sharedptr<const LayoutItem_Field>& layout_field, const Gnome::Gda::Value& field_value)
 {
   if(m_ignore_signals)
@@ -804,8 +804,8 @@ void Box_Data_Details::on_flowtable_field_edited(const sharedptr<const LayoutIte
       //Revert to the value in the database:
       const Gnome::Gda::Value value_old = get_field_value_in_database(field_in_record, window);
       set_entered_field_data(layout_field, value_old);
-   
-      return; 
+
+      return;
     }
 
     //Set the value in all instances of this field in the layout (The field might be on the layout more than once):
@@ -937,7 +937,7 @@ void Box_Data_Details::on_flowtable_field_edited(const sharedptr<const LayoutIte
 void Box_Data_Details::on_userlevel_changed(AppState::userlevels user_level)
 {
 #ifndef GLOM_ENABLE_CLIENT_ONLY
-  m_design_mode = ( user_level == AppState::USERLEVEL_DEVELOPER );    
+  m_design_mode = ( user_level == AppState::USERLEVEL_DEVELOPER );
   m_FlowTable.set_design_mode(m_design_mode);
   // Recreate the layout to correctly set the size of empty flowtables:
   create_layout();
@@ -1075,11 +1075,9 @@ void Box_Data_Details::show_layout_toolbar(bool show)
 
 #endif // !GLOM_ENABLE_CLIENT_ONLY
 
-#ifdef GLOM_ENABLE_MAEMO
 void Box_Data_Details::do_new_record()
 {
   on_button_new();
 }
-#endif
 
 } //namespace Glom
diff --git a/glom/mode_data/box_data_details.h b/glom/mode_data/box_data_details.h
index 4190ef6..9bbd7b4 100644
--- a/glom/mode_data/box_data_details.h
+++ b/glom/mode_data/box_data_details.h
@@ -36,7 +36,7 @@ namespace Glom
 
 class Box_Data_Details : public Box_Data
 {
-public: 
+public:
   Box_Data_Details(bool bWithNavButtons = true);
   virtual ~Box_Data_Details();
 
@@ -46,7 +46,7 @@ public:
 
   virtual void print_layout();
 
- 
+
   //Signals:
 #ifndef GLOM_ENABLE_MAEMO
   typedef sigc::signal<void> type_signal_void;
@@ -69,9 +69,7 @@ public:
   void show_layout_toolbar(bool show = true);
 #endif
 
-  #ifdef GLOM_ENABLE_MAEMO
   void do_new_record();
-  #endif
 
 protected:
 
@@ -79,11 +77,11 @@ protected:
   //Implementations of pure virtual methods from Base_DB_Table_Data:
 public:
   virtual Gnome::Gda::Value get_primary_key_value_selected() const; //Value in the primary key's cell.
-  
+
 protected:
   virtual void set_primary_key_value(const Gtk::TreeModel::iterator& row, const Gnome::Gda::Value& value);
   virtual Gnome::Gda::Value get_primary_key_value(const Gtk::TreeModel::iterator& row) const; //Actual primary key value of this record.
-    
+
   virtual Gnome::Gda::Value get_entered_field_data(const sharedptr<const LayoutItem_Field>& field) const;
   virtual void set_entered_field_data(const sharedptr<const LayoutItem_Field>& field, const Gnome::Gda::Value& value);
   virtual void set_entered_field_data(const Gtk::TreeModel::iterator& row, const sharedptr<const LayoutItem_Field>& field, const Gnome::Gda::Value& value);
@@ -97,11 +95,11 @@ protected:
   void set_found_set_from_primary_key_value();
 
   void print_layout_group(xmlpp::Element* node_parent, const sharedptr<const LayoutGroup>& group);
-  
+
 private:
   //Signal handlers:
   void on_button_new();
-    
+
 #ifndef GLOM_ENABLE_MAEMO
   void on_button_del();
 
@@ -174,7 +172,7 @@ protected:
 
 #endif //GLOM_ENABLE_MAEMO
   type_signal_requested_related_details m_signal_requested_related_details;
-  
+
 #ifndef GLOM_ENABLE_CLIENT_ONLY
   bool m_design_mode; // Cache here because we need it when the layout is redrawn
 #endif
diff --git a/glom/mode_data/notebook_data.cc b/glom/mode_data/notebook_data.cc
index bc0611e..6ab4c67 100644
--- a/glom/mode_data/notebook_data.cc
+++ b/glom/mode_data/notebook_data.cc
@@ -30,7 +30,7 @@ namespace Glom
 {
 
 Notebook_Data::Notebook_Data()
-: 
+:
   #ifdef GLOM_ENABLE_MAEMO
   m_window_maemo_details(0),
   #endif
@@ -46,14 +46,14 @@ Notebook_Data::Notebook_Data()
   #else
   //On Maemo, we add the box to m_window_maemo_details instead:
   m_window_maemo_details = new Window_BoxHolder(&m_Box_Details, _("Details"));
-  
+
   //Let this window have the main AppMenu:
   Hildon::Program::get_instance()->add_window(*m_window_maemo_details);
-  
+
   Gtk::Window* pWindow = get_app_window();
   if(pWindow)
     m_window_maemo_details->set_transient_for(*pWindow);
-    
+
   //Refresh the list when the details window is closed:
   m_window_maemo_details->signal_hide().connect(
     sigc::mem_fun(*this, &Notebook_Data::on_window_maemo_details_closed));
@@ -64,7 +64,7 @@ Notebook_Data::Notebook_Data()
   // Set accessible name for the notebook, to be able to access it via LDTP
 #ifdef GTKMM_ATKMM_ENABLED
   get_accessible()->set_name(_("List Or Details View"));
-#endif  
+#endif
 
 
   //Connect signals:
@@ -82,7 +82,7 @@ Notebook_Data::Notebook_Data()
   //Allow Details to tell List about record deletion:
   m_Box_Details.signal_record_deleted().connect(sigc::mem_fun(m_Box_List, &Box_Data_List::on_details_record_deleted));
   #endif //GLOM_ENABLE_MAEMO
-  
+
   //Allow Details to ask to show a different record in a different table:
   m_Box_Details.signal_requested_related_details().connect(sigc::mem_fun(*this, &Notebook_Data::on_details_user_requested_related_details));
 
@@ -163,8 +163,8 @@ bool Notebook_Data::init_db_details(const FoundSet& found_set, const Gnome::Gda:
       {
         primary_key_for_details = primary_key_value_for_details;
       }
-      
-      //If the specified (or remembered) primary key value is not in the found set, 
+
+      //If the specified (or remembered) primary key value is not in the found set,
       //then ignore it:
       if(!found_set.m_where_clause.empty() && !get_primary_key_is_in_foundset(found_set, primary_key_for_details))
       {
@@ -197,7 +197,7 @@ bool Notebook_Data::init_db_details(const FoundSet& found_set, const Gnome::Gda:
 
   //Select the last-viewed layout, or the details layout, if a specific details record was specified:
   const dataview current_view = get_current_view();
-  
+
   if(details_record_specified)
   {
     if(current_view != DATA_VIEW_Details)
@@ -209,7 +209,7 @@ bool Notebook_Data::init_db_details(const FoundSet& found_set, const Gnome::Gda:
     Glib::ustring current_layout;
     if(!details_record_specified)
     {
-      Document* document = get_document(); 
+      Document* document = get_document();
       if(document)
         current_layout = document->get_layout_current(m_table_name);
     }
@@ -238,30 +238,30 @@ void Notebook_Data::show_details(const Gnome::Gda::Value& primary_key_value)
   //Prevent n_switch_page_handler() from doing the same thing:
   if(m_connection_switch_page)
     m_connection_switch_page.block();
-  
+
   //std::cout << "DEBUG: Notebook_Data::show_details() primary_key_value=" << primary_key_value.to_string() << std::endl;
   m_Box_Details.refresh_data_from_database_with_primary_key(primary_key_value);
 
 #if GLOM_ENABLE_MAEMO
   //Details are shown in a separate window on Maemo,
-  //though that window contains the regular m_Box_Details. 
+  //though that window contains the regular m_Box_Details.
   //TODO: Use the singular form when it's available from the document.
   Document* document = get_document();
   g_assert(document);
-  const Glib::ustring title = 
-    Glib::ustring::compose(_("%1 Details"), 
+  const Glib::ustring title =
+    Glib::ustring::compose(_("%1 Details"),
       document->get_table_title_singular(m_table_name));
   m_window_maemo_details->set_title(title);
-  
+
   m_window_maemo_details->show();
-#else  
+#else
   if(get_current_view() != DATA_VIEW_Details)
     set_current_view(DATA_VIEW_Details);
 #endif
-  
+
   //Re-enable this handler, so we can respond to notebook page changes:
   if(m_connection_switch_page)
-    m_connection_switch_page.unblock();  
+    m_connection_switch_page.unblock();
 }
 
 bool Notebook_Data::on_idle_show_details(const Gnome::Gda::Value& primary_key_value)
@@ -273,7 +273,7 @@ bool Notebook_Data::on_idle_show_details(const Gnome::Gda::Value& primary_key_va
 void Notebook_Data::on_list_user_requested_details(const Gnome::Gda::Value& primary_key_value)
 {
   //Show the details after a delay,
-  //to avoid problems with deleting the list GtkCellRenderer while 
+  //to avoid problems with deleting the list GtkCellRenderer while
   //handling its signal.
   Glib::signal_idle().connect(
     sigc::bind(
@@ -331,7 +331,7 @@ void Notebook_Data::do_menu_developer_layout()
     Box_Data* pBox = dynamic_cast<Box_Data*>(pChild);
     if(pBox)
       pBox->show_layout_dialog();
-  } 
+  }
 }
 
 void Notebook_Data::show_layout_toolbar(bool show)
@@ -389,7 +389,7 @@ void Notebook_Data::on_switch_page_handler(GtkNotebookPage* pPage, guint uiPageN
     if(document)
       document->set_layout_current(m_table_name, box->get_layout_name());
 
-    //And refresh the list view whenever it is shown, to 
+    //And refresh the list view whenever it is shown, to
     //a) show any new records that were added via the details view, or via a related portal elsewhere.
     //b) show changed field contents, changed elsewhere.
     if(box == &m_Box_List)
@@ -414,12 +414,10 @@ void Notebook_Data::get_record_counts(gulong& total, gulong& found)
   m_Box_List.get_record_counts(total, found);
 }
 
-#ifdef GLOM_ENABLE_MAEMO
 void Notebook_Data::do_menu_file_add_record()
 {
   show_details(Gnome::Gda::Value());
   m_Box_Details.do_new_record();
 }
-#endif //GLOM_ENABLE_MAEMO
 
 } //namespace Glom
diff --git a/glom/mode_data/notebook_data.h b/glom/mode_data/notebook_data.h
index cf8f69f..05267b5 100644
--- a/glom/mode_data/notebook_data.h
+++ b/glom/mode_data/notebook_data.h
@@ -25,7 +25,7 @@
 #include <glom/mode_data/box_data_list.h>
 #include <glom/mode_data/box_data_details.h>
 
-#ifdef GLOM_ENABLE_MAEMO 
+#ifdef GLOM_ENABLE_MAEMO
 #include <glom/window_boxholder.h>
 #endif
 
@@ -34,7 +34,7 @@ namespace Glom
 
 class Notebook_Data : public Notebook_Glom
 {
-public: 
+public:
   Notebook_Data();
   virtual ~Notebook_Data();
 
@@ -47,7 +47,7 @@ public:
 
   ///Get the existing where clause, previously supplied to init_db_details().
   FoundSet get_found_set() const;
-  
+
   ///Get the found set for the currently-visible record in the details tab:
   FoundSet get_found_set_details() const;
 
@@ -62,11 +62,9 @@ public:
 #endif // !GLOM_ENABLE_CLIENT_ONLY
 
   virtual void do_menu_file_print(); //override
-  
-  #ifdef GLOM_ENABLE_MAEMO
+
   void do_menu_file_add_record();
-  #endif
-  
+
   void get_record_counts(gulong& total, gulong& found);
 
   enum dataview
@@ -80,7 +78,7 @@ public:
 
   typedef sigc::signal<void, const Glib::ustring&, Gnome::Gda::Value> type_signal_record_details_requested;
   type_signal_record_details_requested signal_record_details_requested();
-  
+
 protected:
 
   ///Show the counts of all records and found records.
@@ -103,14 +101,14 @@ protected:
   //Member widgets:
   Box_Data_List m_Box_List;
   Box_Data_Details m_Box_Details;
-  
+
   #ifdef GLOM_ENABLE_MAEMO //Details are in a separate window on Maemo.
   Window_BoxHolder* m_window_maemo_details;
   #endif
-  
+
   guint m_iPage_Details, m_iPage_List;
   Glib::ustring m_table_name;
-  
+
   type_signal_record_details_requested m_signal_record_details_requested;
 };
 
diff --git a/glom/python_embed/python_module/py_glom_module.cc b/glom/python_embed/python_module/py_glom_module.cc
index 2474644..e036427 100644
--- a/glom/python_embed/python_module/py_glom_module.cc
+++ b/glom/python_embed/python_module/py_glom_module.cc
@@ -60,7 +60,8 @@ BOOST_PYTHON_MODULE(glom_1_14)
   boost::python::class_<PyGlomUI>("UI")
     .def("show_table_details", &PyGlomUI::show_table_details)
     .def("show_table_list", &PyGlomUI::show_table_list)
-    .def("print", &PyGlomUI::print)
+    .def("print_layout", &PyGlomUI::print_layout)
     .def("print_report", &PyGlomUI::print_report)
+    .def("start_new_record", &PyGlomUI::start_new_record)
   ;
 }
diff --git a/tests/test_python_execute_script.cc b/tests/test_python_execute_script.cc
index b495349..84ed165 100644
--- a/tests/test_python_execute_script.cc
+++ b/tests/test_python_execute_script.cc
@@ -5,6 +5,9 @@
 Glib::ustring result_table_name_list;
 Glib::ustring result_table_name_details;
 Gnome::Gda::Value result_primary_key_value_details;
+Glib::ustring result_report_name;
+bool result_printed_layout = false;
+bool result_started_new_record = false;
 
 static void on_script_ui_show_table_list(const Glib::ustring& table_name)
 {
@@ -14,12 +17,27 @@ static void on_script_ui_show_table_list(const Glib::ustring& table_name)
 
 static void on_script_ui_show_table_details(const Glib::ustring& table_name, const Gnome::Gda::Value& primary_key_value)
 {
-  //std::cout << "debug: on_script_ui_show_table_details(): table_name=" << table_name 
+  //std::cout << "debug: on_script_ui_show_table_details(): table_name=" << table_name
   //  << ", primary_key_value=" << primary_key_value.to_string() << std::endl;
   result_table_name_details = table_name;
   result_primary_key_value_details = primary_key_value;
 }
 
+static void on_script_ui_print_report(const Glib::ustring& report_name)
+{
+  result_report_name = report_name;;
+}
+
+static void on_script_ui_print_layout()
+{
+  result_printed_layout = true;
+}
+
+static void on_script_ui_start_new_record()
+{
+  result_started_new_record = true;
+}
+
 int main()
 {
   Glom::libglom_init(); //Also initializes python.
@@ -27,24 +45,34 @@ int main()
   const Glib::ustring table_name_input = "sometable";
   const Glib::ustring table_name_details_input = "artists";
   const Gnome::Gda::Value primary_key_value_input(123);
-  
+  const Glib::ustring report_name_input = "somereport";
+
   //Just some code to make sure that the python API exists:
-  const Glib::ustring script = 
+  const Glib::ustring script =
     "table_name = record.table_name;\n"
     "ui.show_table_list(table_name);\n"
-    "ui.show_table_details(\"" + table_name_details_input + "\", " + primary_key_value_input.to_string() + ")\n";
+    "ui.show_table_details(\"" + table_name_details_input + "\", " + primary_key_value_input.to_string() + ");\n"
+    "ui.print_report(\"" + report_name_input + "\");\n"
+    "ui.print_layout();\n"
+    "ui.start_new_record();\n";
   Glom::type_map_fields field_values;
   Glib::RefPtr<Gnome::Gda::Connection> connection;
-    
+
   Glom::PythonUICallbacks callbacks;
-  callbacks.m_slot_show_table_list = 
+  callbacks.m_slot_show_table_list =
     sigc::ptr_fun(&on_script_ui_show_table_list);
-  callbacks.m_slot_show_table_details = 
-    sigc::ptr_fun(&on_script_ui_show_table_details);     
-      
+  callbacks.m_slot_show_table_details =
+    sigc::ptr_fun(&on_script_ui_show_table_details);
+  callbacks.m_slot_print_report =
+    sigc::ptr_fun(&on_script_ui_print_report);
+  callbacks.m_slot_print_layout =
+    sigc::ptr_fun(&on_script_ui_print_layout);
+  callbacks.m_slot_start_new_record =
+    sigc::ptr_fun(&on_script_ui_start_new_record);
+
   //Execute a python script:
   try
-  { 
+  {
     Glom::glom_execute_python_function_implementation(
       script, field_values,
       0 /* document */, table_name_input,
@@ -62,11 +90,14 @@ int main()
     std::cerr << "Exception: boost::python::error_already_set" << std::endl;
     return EXIT_FAILURE;
   }
-  
+
   //Check that the callbacks received the expected values:
   g_assert(result_table_name_list == table_name_input);
   g_assert(result_table_name_details == table_name_details_input);
-  g_assert(result_primary_key_value_details == primary_key_value_input); 
+  g_assert(result_primary_key_value_details == primary_key_value_input);
+  g_assert(result_report_name == report_name_input);
+  g_assert(result_printed_layout);
+  g_assert(result_started_new_record);
 
   return EXIT_SUCCESS;
 }



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]