Commit 8364855d authored by Murray Cumming's avatar Murray Cumming
Browse files

Glade instantiation: Simplify, make more robust, and test.

  * glom/glade_utils.h: get_glade_widget_derived_with_warning():
  Don'te an ID. This requires the class to have a static glade_id member and
  glade_developer (bool) member, telling us what file and what ID to use.
  This associates the IDs and filenames with the class, instead of being in other files,
  to avoid duplication and to avoid using the wrong ones.
  This allows us to remove get_glade_developer_widget_derived_with_warning().
  * Many files: Use these new methods, to avoid mentioning glade IDs.
  * tests/test_glade_derived_instantiation.cc: Try to instantiate all the known
  derived glade dialogs.
parent 0f6e8df3
......@@ -23,6 +23,19 @@
* glom/base_db.cc: offer_item_formatting(): Remove a useless use of
Gtk::Builder.
 
2010-04-10 Murray Cumming <murrayc@murrayc.com>
Glade instantiation: Simplify, make more robust, and test.
* glom/glade_utils.h: get_glade_widget_derived_with_warning(),
get_glade_developer_widget_derived_with_warning(): Add method overloads that
don't take an ID. These require the class to have a static glade_id member.
This associates the IDs with the class, instead of being in other files,
to avoid duplication and to avoid using the wrong ones.
* Many files: Use these new methods, to avoid mentioning glade IDs.
* tests/test_glade_derived_instantiation.cc: Try to instantiate all the known
derived glade dialogs.
2010-04-10 Murray Cumming <murrayc@murrayc.com>
 
Notebook properties dialog: Fix a probable crash.
......
......@@ -15,7 +15,7 @@
## You should have received a copy of the GNU General Public License
## along with this program. If not, see <http://www.gnu.org/licenses/>.
glom_glom_SOURCES = \
glom_source_files = \
glom/application.cc \
glom/application.h \
glom/base_db.cc \
......@@ -48,7 +48,6 @@ glom_glom_SOURCES = \
glom/glom_postgres.h \
glom/glom_privs.cc \
glom/glom_privs.h \
glom/main.cc \
glom/notebook_glom.cc \
glom/notebook_glom.h \
glom/signal_reemitter.h \
......@@ -208,7 +207,7 @@ glom_glom_SOURCES = \
glom/utility_widgets/db_adddel/glom_db_treemodel.h
if !GLOM_ENABLE_CLIENT_ONLY
glom_glom_SOURCES += \
glom_source_files += \
glom/mode_design/dialog_database_preferences.cc \
glom/mode_design/dialog_database_preferences.h \
glom/mode_design/dialog_initial_password.cc \
......@@ -342,22 +341,28 @@ glom_glom_SOURCES += \
endif
if !GLOM_ENABLE_MAEMO
glom_glom_SOURCES += \
glom_source_files += \
glom/navigation/box_tables.cc \
glom/navigation/box_tables.h
else
glom_glom_SOURCES += \
glom_source_files += \
glom/navigation/maemo/pickerbutton_table.cc \
glom/navigation/maemo/pickerbutton_table.h
endif
glom_glom_LDADD = $(win_resfile) \
glom_glom_SOURCES = \
glom/main.cc \
$(glom_source_files)
glom_all_libs = $(win_resfile) \
glom/libglom/libglom-$(GLOM_ABI_VERSION).la \
$(GLOM_LIBS) $(PYTHON_LIBS) $(BOOST_PYTHON_LIBS) $(INTLLIBS)
if !GLOM_ENABLE_MAEMO
glom_glom_LDADD += -lgettextpo
glom_all_libs += -lgettextpo
endif
glom_glom_LDADD = $(glom_all_libs)
if HOST_WIN32
# Suppress console window
glom_glom_LDFLAGS = -mwindows
......
......@@ -30,6 +30,7 @@ check_PROGRAMS = \
tests/test_python_execute_script \
tests/import/test_parsing \
tests/import/test_signals \
tests/test_glade_derived_instantiation \
tests/glade_toplevels_instantiation
TESTS = tests/test_parsing_time \
......@@ -37,11 +38,13 @@ TESTS = tests/test_parsing_time \
tests/test_dtd_file_validation.sh \
tests/test_glade_file_validation.sh \
tests/test_glade_toplevels_instantiation.sh \
tests/test_glade_derived_instantiation \
tests/test_load_python_library \
tests/test_python_module \
tests/test_python_execute_func \
tests/test_python_execute_func_date \
tests/test_python_execute_script
# These hang most of the time, but not always:
# tests/import/test_parsing \
# tests/import/test_signals
......@@ -83,6 +86,7 @@ tests_import_test_signals_SOURCES = \
tests/import/utils.cc\
tests/import/utils.h\
tests/import/test_signals.cc
tests_test_glade_derived_instantiation_SOURCES = tests/test_glade_derived_instantiation.cc $(glom_source_files)
glom_libglom_test_connectionpool_LDADD = $(tests_ldadd)
glom_libglom_test_document_LDADD = $(tests_ldadd)
......@@ -125,3 +129,4 @@ tests_test_python_execute_func_date_LDADD = $(tests_ldadd) $(GLOM_LIBS) $(PYTHON
tests_test_python_execute_script_LDADD = $(tests_ldadd) $(GLOM_LIBS) $(PYTHON_LIBS)
tests_import_test_parsing_LDADD = $(LIBGLOM_LIBS) $(GLOM_LIBS)
tests_import_test_signals_LDADD = $(LIBGLOM_LIBS) $(GLOM_LIBS)
tests_test_glade_derived_instantiation_LDADD = $(glom_all_libs)
......@@ -72,6 +72,9 @@ namespace Glom
// Global application variable
Application* global_application = 0;
const char* Application::glade_id("window_main");
const bool Application::glade_developer(false);
Application::Application(BaseObjectType* cobject, const Glib::RefPtr<Gtk::Builder>& builder)
: type_base(cobject, "Glom"),
m_pBoxTop(0),
......@@ -710,7 +713,7 @@ void Application::open_browsed_document(const EpcServiceInfo* server, const Glib
//Request a password to attempt retrieval of the document over the network:
Dialog_Connection* dialog_connection = 0;
//Load the Glade file and instantiate its widgets to get the dialog stuff:
Utils::get_glade_widget_derived_with_warning("dialog_connection", dialog_connection);
Utils::get_glade_widget_derived_with_warning(dialog_connection);
dialog_connection->set_transient_for(*this);
dialog_connection->set_connect_to_browsed();
dialog_connection->set_database_name(service_name);
......@@ -1381,29 +1384,9 @@ bool Application::offer_new_or_existing()
{
//Offer to load an existing document, or start a new one.
const Glib::ustring glade_path = Utils::get_glade_file_path("glom.glade");
Glib::RefPtr<Gtk::Builder> refXml;
#ifdef GLIBMM_EXCEPTIONS_ENABLED
try
{
refXml = Gtk::Builder::create_from_file(glade_path, "dialog_existing_or_new");
}
catch(const Glib::Error& ex)
{
std::cerr << "Application::offer_new_or_existing(): Gtk::Builder::create_from_file() failed: " << ex.what() << std::endl;
}
#else
std::auto_ptr<Glib::Error> ex;
refXml = Gtk::Builder::create_from_file(glade_path, "dialog_existing_or_new", ex);
if(ex.get())
{
std::cerr << "Application::offer_new_or_existing(): Gtk::Builder::create_from_file() failed:" << ex->what() << std::endl;
}
#endif
g_assert(refXml);
Dialog_ExistingOrNew* dialog_raw = 0;
refXml->get_widget_derived("dialog_existing_or_new", dialog_raw);
Utils::get_glade_widget_derived_with_warning(dialog_raw);
std::auto_ptr<Dialog_ExistingOrNew> dialog(dialog_raw);
dialog->set_transient_for(*this);
/*
......@@ -1664,25 +1647,17 @@ bool Application::recreate_database(bool& user_cancelled)
//Show the user that something is happening, because the INSERTS might take time.
//TOOD: This doesn't actually show up until near the end, even with Gtk::Main::instance()->iteration().
std::auto_ptr<Dialog_ProgressCreating> dialog_progress;
Glib::RefPtr<Gtk::Builder> refXml = Gtk::Builder::create_from_file(Utils::get_glade_file_path("glom.glade"), "window_progress");
if(refXml)
{
Dialog_ProgressCreating* dialog_progress_temp = 0;
refXml->get_widget_derived("window_progress", dialog_progress_temp);
if(dialog_progress_temp)
{
dialog_progress_temp->set_message(_("Creating Glom Database"), _("Creating Glom database from example file."));
dialog_progress.reset(dialog_progress_temp); //Put the dialog in an auto_ptr so that it will be deleted (and hidden) when the current function returns.
Dialog_ProgressCreating* dialog_progress_temp = 0;
Utils::get_glade_widget_derived_with_warning(dialog_progress_temp);
dialog_progress_temp->set_message(_("Creating Glom Database"), _("Creating Glom database from example file."));
std::auto_ptr<Dialog_ProgressCreating> dialog_progress(dialog_progress_temp); //Put the dialog in an auto_ptr so that it will be deleted (and hidden) when the current function returns.
dialog_progress->set_transient_for(*this);
dialog_progress->show();
dialog_progress->set_transient_for(*this);
dialog_progress->show();
//Ensure that the dialog is shown, instead of waiting for the application to be idle:
while(Gtk::Main::instance()->events_pending())
Gtk::Main::instance()->iteration();
}
}
//Ensure that the dialog is shown, instead of waiting for the application to be idle:
while(Gtk::Main::instance()->events_pending())
Gtk::Main::instance()->iteration();
dialog_progress->pulse();
......@@ -2444,41 +2419,34 @@ void Application::stop_self_hosting_of_document_database()
void Application::on_menu_developer_changelanguage()
{
Glib::RefPtr<Gtk::Builder> refXml = Gtk::Builder::create_from_file(Utils::get_glade_file_path("glom_developer.glade"), "dialog_change_language");
if(refXml)
{
Dialog_ChangeLanguage* dialog = 0;
refXml->get_widget_derived("dialog_change_language", dialog);
if(dialog)
{
dialog->set_icon_name("glom");
dialog->set_transient_for(*this);
const int response = Glom::Utils::dialog_run_with_help(dialog, "dialog_change_language");
dialog->hide();
if(response == Gtk::RESPONSE_OK)
{
TranslatableItem::set_current_locale(dialog->get_locale());
Dialog_ChangeLanguage* dialog = 0;
Utils::get_glade_widget_derived_with_warning(dialog);
dialog->set_icon_name("glom");
dialog->set_transient_for(*this);
const int response = Glom::Utils::dialog_run_with_help(dialog, "dialog_change_language");
dialog->hide();
//Get the translations from the document (in Operator mode, we only load the necessary translations.)
//This also updates the UI, so we show all the translated titles:
int failure_code = 0;
get_document()->load(failure_code);
if(response == Gtk::RESPONSE_OK)
{
TranslatableItem::set_current_locale(dialog->get_locale());
m_pFrame->show_table_refresh(); //load() doesn't seem to refresh the view.
}
//Get the translations from the document (in Operator mode, we only load the necessary translations.)
//This also updates the UI, so we show all the translated titles:
int failure_code = 0;
get_document()->load(failure_code);
delete dialog;
}
m_pFrame->show_table_refresh(); //load() doesn't seem to refresh the view.
}
delete dialog;
}
void Application::on_menu_developer_translations()
{
if(!m_window_translations)
{
Glib::RefPtr<Gtk::Builder> refXml = Gtk::Builder::create_from_file(Utils::get_glade_file_path("glom_developer.glade"), "window_translations");
refXml->get_widget_derived("window_translations", m_window_translations);
Utils::get_glade_widget_derived_with_warning(m_window_translations);
if(m_window_translations)
{
m_pFrame->add_view(m_window_translations);
......
......@@ -56,6 +56,9 @@ class Window_Translations;
class Application : public GlomBakery::App_WithDoc_Gtk
{
public:
static const char* glade_id;
static const bool glade_developer;
Application(BaseObjectType* cobject, const Glib::RefPtr<Gtk::Builder>& builder);
virtual ~Application();
......
......@@ -1815,30 +1815,8 @@ sharedptr<LayoutItem_Field> Base_DB::offer_field_list_select_one_field(const sha
{
sharedptr<LayoutItem_Field> result;
Glib::RefPtr<Gtk::Builder> refXml;
#ifdef GLIBMM_EXCEPTIONS_ENABLED
try
{
refXml = Gtk::Builder::create_from_file(Utils::get_glade_file_path("glom_developer.glade"), "dialog_choose_field");
}
catch(const Gtk::BuilderError& ex)
{
std::cerr << ex.what() << std::endl;
return result;
}
#else
std::auto_ptr<Glib::Error> error;
refXml = Gtk::Builder::create_from_file(Utils::get_glade_file_path("glom_developer.glade"), "dialog_choose_field", error);
if (error.get())
{
std::cerr << error->what() << std::endl;
return result;
}
#endif
Dialog_ChooseField* dialog = 0;
refXml->get_widget_derived("dialog_choose_field", dialog);
Utils::get_glade_widget_derived_with_warning(dialog);
if(dialog)
{
......@@ -1865,30 +1843,8 @@ Base_DB::type_list_field_items Base_DB::offer_field_list(const Glib::ustring& ta
{
type_list_field_items result;
Glib::RefPtr<Gtk::Builder> refXml;
#ifdef GLIBMM_EXCEPTIONS_ENABLED
try
{
refXml = Gtk::Builder::create_from_file(Utils::get_glade_file_path("glom_developer.glade"), "dialog_choose_field");
}
catch(const Gtk::BuilderError& ex)
{
std::cerr << ex.what() << std::endl;
return result;
}
#else
std::auto_ptr<Glib::Error> error;
refXml = Gtk::Builder::create_from_file(Utils::get_glade_file_path("glom_developer.glade"), "dialog_choose_field", error);
if (error.get())
{
std::cerr << error->what() << std::endl;
return result;
}
#endif
Dialog_ChooseField* dialog = 0;
refXml->get_widget_derived("dialog_choose_field", dialog);
Utils::get_glade_widget_derived_with_warning(dialog);
if(dialog)
{
......@@ -1913,31 +1869,24 @@ bool Base_DB::offer_item_formatting(const sharedptr<LayoutItem_WithFormatting>&
{
bool result = false;
try
{
Dialog_Formatting dialog;
if(transient_for)
dialog.set_transient_for(*transient_for);
Dialog_Formatting dialog;
if(transient_for)
dialog.set_transient_for(*transient_for);
add_view(&dialog);
add_view(&dialog);
dialog.set_item(layout_item);
const int response = dialog.run();
if(response == Gtk::RESPONSE_OK)
{
//Get the chosen formatting:
dialog.use_item_chosen(layout_item);
result = true;
}
//Cancel means use the old one:
dialog.set_item(layout_item);
remove_view(&dialog);
}
catch(const Gtk::BuilderError& ex)
const int response = dialog.run();
if(response == Gtk::RESPONSE_OK)
{
std::cerr << ex.what() << std::endl;
//Get the chosen formatting:
dialog.use_item_chosen(layout_item);
result = true;
}
//Cancel means use the old one:
remove_view(&dialog);
return result;
}
......@@ -1946,40 +1895,28 @@ sharedptr<LayoutItem_Field> Base_DB::offer_field_formatting(const sharedptr<cons
{
sharedptr<LayoutItem_Field> result;
try
{
Glib::RefPtr<Gtk::Builder> refXml = Gtk::Builder::create_from_file(Utils::get_glade_file_path("glom_developer.glade"), "dialog_layout_field_properties");
Dialog_FieldLayout* dialog = 0;
refXml->get_widget_derived("dialog_layout_field_properties", dialog);
Dialog_FieldLayout* dialog = 0;
Utils::get_glade_widget_derived_with_warning(dialog);
if(dialog)
{
if(transient_for)
dialog->set_transient_for(*transient_for);
if(transient_for)
dialog->set_transient_for(*transient_for);
add_view(dialog);
add_view(dialog);
dialog->set_field(start_field, table_name);
dialog->set_field(start_field, table_name);
const int response = dialog->run();
if(response == Gtk::RESPONSE_OK)
{
//Get the chosen field:
result = dialog->get_field_chosen();
}
else if(start_field) //Cancel means use the old one:
result = glom_sharedptr_clone(start_field);
remove_view(dialog);
delete dialog;
}
}
catch(const Gtk::BuilderError& ex)
const int response = dialog->run();
if(response == Gtk::RESPONSE_OK)
{
std::cerr << ex.what() << std::endl;
//Get the chosen field:
result = dialog->get_field_chosen();
}
else if(start_field) //Cancel means use the old one:
result = glom_sharedptr_clone(start_field);
remove_view(dialog);
delete dialog;
return result;
}
......@@ -1988,34 +1925,23 @@ sharedptr<LayoutItem_Text> Base_DB::offer_textobject(const sharedptr<LayoutItem_
{
sharedptr<LayoutItem_Text> result = start_textobject;
try
{
Glib::RefPtr<Gtk::Builder> refXml = Gtk::Builder::create_from_file(Utils::get_glade_file_path("glom_developer.glade"), "window_textobject");
Dialog_TextObject* dialog = 0;
refXml->get_widget_derived("window_textobject", dialog);
if(dialog)
{
if(transient_for)
dialog->set_transient_for(*transient_for);
dialog->set_textobject(start_textobject, Glib::ustring(), show_title);
int response = Glom::Utils::dialog_run_with_help(dialog, "window_textobject");
dialog->hide();
if(response == Gtk::RESPONSE_OK)
{
//Get the chosen relationship:
result = dialog->get_textobject();
}
Dialog_TextObject* dialog = 0;
Utils::get_glade_widget_derived_with_warning(dialog);
if(transient_for)
dialog->set_transient_for(*transient_for);
delete dialog;
}
}
catch(const Gtk::BuilderError& ex)
dialog->set_textobject(start_textobject, Glib::ustring(), show_title);
const int response = Glom::Utils::dialog_run_with_help(dialog, "window_textobject");
dialog->hide();
if(response == Gtk::RESPONSE_OK)
{
std::cerr << ex.what() << std::endl;
//Get the chosen relationship:
result = dialog->get_textobject();
}
delete dialog;
return result;
}
......@@ -2023,34 +1949,23 @@ sharedptr<LayoutItem_Image> Base_DB::offer_imageobject(const sharedptr<LayoutIte
{
sharedptr<LayoutItem_Image> result = start_imageobject;
try
{
Glib::RefPtr<Gtk::Builder> refXml = Gtk::Builder::create_from_file(Utils::get_glade_file_path("glom_developer.glade"), "window_imageobject");
Dialog_ImageObject* dialog = 0;
refXml->get_widget_derived("window_imageobject", dialog);
if(dialog)
{
if(transient_for)
dialog->set_transient_for(*transient_for);
dialog->set_imageobject(start_imageobject, Glib::ustring(), show_title);
const int response = Glom::Utils::dialog_run_with_help(dialog, "window_imageobject");
dialog->hide();
if(response == Gtk::RESPONSE_OK)
{
//Get the chosen relationship:
result = dialog->get_imageobject();
}
Dialog_ImageObject* dialog = 0;
Utils::get_glade_widget_derived_with_warning(dialog);
if(transient_for)
dialog->set_transient_for(*transient_for);
delete dialog;
}
}
catch(const Gtk::BuilderError& ex)
dialog->set_imageobject(start_imageobject, Glib::ustring(), show_title);
const int response = Glom::Utils::dialog_run_with_help(dialog, "window_imageobject");
dialog->hide();
if(response == Gtk::RESPONSE_OK)
{
std::cerr << ex.what() << std::endl;
//Get the chosen relationship:
result = dialog->get_imageobject();
}
delete dialog;
return result;
}
......@@ -2058,35 +1973,24 @@ sharedptr<LayoutItem_Notebook> Base_DB::offer_notebook(const sharedptr<LayoutIte
{
sharedptr<LayoutItem_Notebook> result = start_notebook;
try
{
Glib::RefPtr<Gtk::Builder> refXml = Gtk::Builder::create_from_file(Utils::get_glade_file_path("glom_developer.glade"), "dialog_notebook");
Dialog_Notebook* dialog = 0;
refXml->get_widget_derived("dialog_notebook", dialog);
if(dialog)
{
if(transient_for)
dialog->set_transient_for(*transient_for);
Dialog_Notebook* dialog = 0;
Utils::get_glade_widget_derived_with_warning(dialog);
if(transient_for)
dialog->set_transient_for(*transient_for);
dialog->set_notebook(start_notebook);
//dialog->set_transient_for(*this);
const int response = Glom::Utils::dialog_run_with_help(dialog, "dialog_notebook");
dialog->hide();
if(response == Gtk::RESPONSE_OK)
{
//Get the chosen relationship:
result = dialog->get_notebook();
}
delete dialog;
}
}
catch(const Gtk::BuilderError& ex)
dialog->set_notebook(start_notebook);
//dialog->set_transient_for(*this);
const int response = Glom::Utils::dialog_run_with_help(dialog, "dialog_notebook");
dialog->hide();
if(response == Gtk::RESPONSE_OK)
{
std::cerr << ex.what() << std::endl;
//Get the chosen relationship:
result = dialog->get_notebook();
}
delete dialog;
return result;
}
#endif // !GLOM_ENABLE_CLIENT_ONLY
......
......@@ -25,6 +25,9 @@
namespace Glom
{
const char* Box_Reports::glade_id("box_reports");
const bool Box_Reports::glade_developer(true);
Box_Reports::Box_Reports(BaseObjectType* cobject, const Glib::RefPtr<Gtk::Builder>& builder)
: Box_DB_Table(cobject, builder),
m_colReportName(0),
......
......@@ -30,6 +30,9 @@ namespace Glom
class Box_Reports : public Box_DB_Table
{
public:
static const char* glade_id;
static const bool glade_developer;
Box_Reports(BaseObjectType* cobject, const Glib::RefPtr<Gtk::Builder>& builder);
virtual ~Box_Reports();
......
......@@ -32,6 +32,9 @@
namespace Glom
{
const char* Dialog_Connection::glade_id("dialog_connection");
const bool Dialog_Connection::glade_developer(false);
Dialog_Connection::Dialog_Connection(BaseObjectType* cobject, const Glib::RefPtr<Gtk::Builder>& builder)
: Gtk::Dialog(cobject),
Base_DB(),
......
......@@ -36,6 +36,9 @@ class Dialog_Connection