91
108
m_pDialog_Relationships(0),
92
109
m_dialog_addrelatedtable(0),
93
110
m_dialog_relationships_overview(0),
111
m_dialog_progess_connection_initialize(0),
94
112
#endif // !GLOM_ENABLE_CLIENT_ONLY
113
m_dialog_progess_connection_startup(0),
114
m_dialog_progess_connection_cleanup(0),
95
115
m_pDialogConnection(0)
97
117
//Load widgets from glade file:
98
refGlade->get_widget("label_name", m_pLabel_Name);
99
refGlade->get_widget("label_table_name", m_pLabel_Table);
118
builder->get_widget("label_table_name", m_pLabel_Table);
101
refGlade->get_widget("hbox_footer", m_box_footer);
102
refGlade->get_widget("label_mode", m_pLabel_Mode);
103
refGlade->get_widget("label_user_level", m_pLabel_userlevel);
120
builder->get_widget("hbox_header", m_box_header);
121
builder->get_widget("hbox_footer", m_box_footer);
122
builder->get_widget("label_mode", m_pLabel_Mode);
123
builder->get_widget("label_user_level", m_pLabel_userlevel);
105
//Hide the footer on maemo (It takes too much space),
125
//Hide unnecessary widgets on maemo that take too much space,
106
126
//and reduce the border width:
107
127
#ifdef GLOM_ENABLE_MAEMO
128
m_box_header->hide();
108
129
m_box_footer->hide();
109
130
set_border_width(Glom::Utils::DEFAULT_SPACING_LARGE);
112
refGlade->get_widget("hbox_quickfind", m_pBox_QuickFind);
113
m_pBox_QuickFind->hide();
115
refGlade->get_widget("entry_quickfind", m_pEntry_QuickFind);
134
//We don't use Glade for these, so it easier to modify them for the Maemo port.
135
m_pBox_QuickFind = Gtk::manage(new Gtk::HBox(false, Utils::DEFAULT_SPACING_SMALL));
136
Gtk::Label* label = Gtk::manage(new Gtk::Label(_("Quick Find")));
137
m_pBox_QuickFind->pack_start(*label, Gtk::PACK_SHRINK);
139
#ifndef GLOM_ENABLE_MAEMO
140
m_pEntry_QuickFind = Gtk::manage(new Gtk::Entry());
142
m_pEntry_QuickFind = Gtk::manage(new Hildon::Entry(Gtk::Hildon::SIZE_AUTO));
116
144
m_pEntry_QuickFind->signal_activate().connect(
117
145
sigc::mem_fun(*this, &Frame_Glom::on_button_quickfind) ); //Pressing Enter here is like pressing Find.
119
refGlade->get_widget("button_quickfind", m_pButton_QuickFind);
147
m_pBox_QuickFind->pack_start(*m_pEntry_QuickFind, Gtk::PACK_EXPAND_WIDGET);
148
#ifndef GLOM_ENABLE_MAEMO
149
m_pButton_QuickFind = Gtk::manage(new Gtk::Button(_("_Find"), true));
151
m_pButton_QuickFind = Gtk::manage(new Hildon::Button(Gtk::Hildon::SIZE_AUTO,
152
Hildon::BUTTON_ARRANGEMENT_VERTICAL, _("Find"), _("Search for records")));
120
154
m_pButton_QuickFind->signal_clicked().connect(
121
155
sigc::mem_fun(*this, &Frame_Glom::on_button_quickfind) );
123
refGlade->get_widget("hbox_records_count", m_pBox_RecordsCount);
124
refGlade->get_widget("label_records_count", m_pLabel_RecordsCount);
125
refGlade->get_widget("label_records_found_count", m_pLabel_FoundCount);
126
refGlade->get_widget("button_find_all", m_pButton_FindAll);
156
m_pBox_QuickFind->pack_start(*m_pButton_QuickFind, Gtk::PACK_SHRINK);
158
m_pBox_QuickFind->show_all_children();
159
m_pBox_QuickFind->hide();
161
#ifndef GLOM_ENABLE_MAEMO
162
PlaceHolder* placeholder_quickfind = 0;
163
builder->get_widget_derived("vbox_quickfind", placeholder_quickfind);
164
placeholder_quickfind->add(*m_pBox_QuickFind);
165
#endif //GLOM_ENABLE_MAEMO
168
builder->get_widget("hbox_records_count", m_pBox_RecordsCount);
169
builder->get_widget("label_records_count", m_pLabel_RecordsCount);
170
builder->get_widget("label_records_found_count", m_pLabel_FoundCount);
171
builder->get_widget("button_find_all", m_pButton_FindAll);
127
172
m_pButton_FindAll->signal_clicked().connect(
128
173
sigc::mem_fun(*this, &Frame_Glom::on_button_find_all) );
130
refGlade->get_widget_derived("vbox_mode", m_pBox_Mode);
132
//m_pLabel_Mode->set_text(_("No database selected.\n Use the Navigation menu, or open a previous Glom document."));
175
builder->get_widget_derived("vbox_mode", m_pBox_Mode);
134
177
m_Mode = MODE_None;
135
178
m_Mode_Previous = MODE_None;
336
408
show_table(m_table_name);
339
void Frame_Glom::show_table(const Glib::ustring& table_name, const Gnome::Gda::Value& primary_key_value_for_details)
411
void Frame_Glom::show_table_allow_empty(const Glib::ustring& table_name, const Gnome::Gda::Value& primary_key_value_for_details)
341
413
App_Glom* pApp = dynamic_cast<App_Glom*>(get_app_window());
343
415
//This can take quite a long time, so we show the busy cursor while it's working:
344
Bakery::BusyCursor busy_cursor(pApp);
346
//Check that there is a table to show:
347
if(table_name.empty())
353
//Choose a default mode, if necessary:
354
if(m_Mode == MODE_None)
358
m_table_name = table_name;
359
Glib::ustring strMode;
416
BusyCursor busy_cursor(pApp);
418
//Choose a default mode, if necessary:
419
if(m_Mode == MODE_None)
423
m_table_name = table_name;
424
Glib::ustring strMode;
360
425
#ifndef GLOM_ENABLE_CLIENT_ONLY
361
//Update the document with any new information in the database if necessary (though the database _should never have changed information)
362
update_table_in_document_from_database();
426
//Update the document with any new information in the database if necessary (though the database _should never have changed information)
427
update_table_in_document_from_database();
363
428
#endif // !GLOM_ENABLE_CLIENT_ONLY
365
//Update user-level dependent UI:
367
on_userlevel_changed(pApp->get_userlevel());
430
//Update user-level dependent UI:
432
on_userlevel_changed(pApp->get_userlevel());
376
//Start with the last-used found set (sort order and where clause)
378
//(This would be ignored anyway if a details primary key is specified.)
379
Document_Glom* document = get_document();
381
found_set = document->get_criteria_current(m_table_name);
383
//Make sure that this is set:
384
found_set.m_table_name = m_table_name;
386
//If there is no saved sort clause,
387
//then sort by the ID, just so we sort by something, so that the order is predictable:
388
if(found_set.m_sort_clause.empty())
390
sharedptr<Field> field_primary_key = get_field_primary_key_for_table(m_table_name);
391
if(field_primary_key)
393
sharedptr<LayoutItem_Field> layout_item_sort = sharedptr<LayoutItem_Field>::create();
394
layout_item_sort->set_full_field_details(field_primary_key);
396
found_set.m_sort_clause.clear();
398
//Avoid the sort clause if the found set will include too many records,
399
//because that would be too slow.
400
//The user can explicitly request a sort later, by clicking on a column header.
401
//TODO_Performance: This causes an almost-duplicate COUNT query (we do it in the treemodel too), but it's not that slow.
402
sharedptr<LayoutItem_Field> layout_item_temp = sharedptr<LayoutItem_Field>::create();
403
layout_item_temp->set_full_field_details(field_primary_key);
404
type_vecLayoutFields layout_fields;
405
layout_fields.push_back(layout_item_temp);
406
const Glib::ustring sql_query_without_sort = Utils::build_sql_select_with_where_clause(found_set.m_table_name, layout_fields, found_set.m_where_clause, found_set.m_extra_join, type_sort_clause(), found_set.m_extra_group_by);
407
const int count = Base_DB::count_rows_returned_by(sql_query_without_sort);
408
if(count < 10000) //Arbitrary large number.
409
found_set.m_sort_clause.push_back( type_pair_sort_field(layout_item_sort, true /* ascending */) );
441
//Start with the last-used found set (sort order and where clause)
443
//(This would be ignored anyway if a details primary key is specified.)
444
Document* document = get_document();
446
found_set = document->get_criteria_current(m_table_name);
448
//Make sure that this is set:
449
found_set.m_table_name = m_table_name;
451
//If there is no saved sort clause,
452
//then sort by the ID, just so we sort by something, so that the order is predictable:
453
if(found_set.m_sort_clause.empty())
455
sharedptr<Field> field_primary_key = get_field_primary_key_for_table(m_table_name);
456
if(field_primary_key)
458
sharedptr<LayoutItem_Field> layout_item_sort = sharedptr<LayoutItem_Field>::create();
459
layout_item_sort->set_full_field_details(field_primary_key);
461
found_set.m_sort_clause.clear();
463
//Avoid the sort clause if the found set will include too many records,
464
//because that would be too slow.
465
//The user can explicitly request a sort later, by clicking on a column header.
466
//TODO_Performance: This causes an almost-duplicate COUNT query (we do it in the treemodel too), but it's not that slow.
467
sharedptr<LayoutItem_Field> layout_item_temp = sharedptr<LayoutItem_Field>::create();
468
layout_item_temp->set_full_field_details(field_primary_key);
469
type_vecLayoutFields layout_fields;
470
layout_fields.push_back(layout_item_temp);
471
const Glib::ustring sql_query_without_sort = Utils::build_sql_select_with_where_clause(found_set.m_table_name, layout_fields, found_set.m_where_clause, found_set.m_extra_join, type_sort_clause(), found_set.m_extra_group_by);
472
const int count = Base_DB::count_rows_returned_by(sql_query_without_sort);
473
if(count < 10000) //Arbitrary large number.
474
found_set.m_sort_clause.push_back( type_pair_sort_field(layout_item_sort, true /* ascending */) );
413
//Show the wanted records in the notebook, showing details for a particular record if wanted:
414
m_Notebook_Data.init_db_details(found_set, primary_key_value_for_details);
415
set_mode_widget(m_Notebook_Data);
417
//Show how many records were found:
418
update_records_count();
425
m_Notebook_Find.init_db_details(m_table_name);
426
set_mode_widget(m_Notebook_Find);
431
std::cout << "Frame_Glom::on_box_tables_selected(): Unexpected mode" << std::endl;
432
strMode = _("Unknown");
437
m_pLabel_Mode->set_text(strMode);
478
//Show the wanted records in the notebook, showing details for a particular record if wanted:
479
m_Notebook_Data.init_db_details(found_set, primary_key_value_for_details);
480
set_mode_widget(m_Notebook_Data);
482
//Show how many records were found:
483
update_records_count();
490
m_Notebook_Find.init_db_details(m_table_name, get_active_layout_platform(get_document()));
491
set_mode_widget(m_Notebook_Find);
496
std::cout << "Frame_Glom::on_box_tables_selected(): Unexpected mode" << std::endl;
497
strMode = _("Unknown");
502
m_pLabel_Mode->set_text(strMode);
440
504
show_table_title();
442
506
//List the reports and print layouts in the menus:
946
void Frame_Glom::on_menu_file_toggle_share(const Glib::RefPtr<Gtk::ToggleAction>& action)
950
std::cerr << "Frame_Glom::on_menu_file_toggle_share(): action was null." << std::endl;
953
//Prevent this change if not in developer mode,
954
//though the menu item should be disabled then anyway.
955
Document* document = dynamic_cast<Document*>(get_document());
956
if(!document || document->get_userlevel() != AppState::USERLEVEL_DEVELOPER)
959
bool shared = action->get_active(); //Whether it should be shared.
960
if(shared == document->get_network_shared())
962
//Do nothing, because things are already as requested.
963
//This is probably just an extra signal emitted when we set the toggle in the UI.
964
//So we avoid the endless loop:
970
//Ask user for confirmation:
971
//TODO: Warn that this will be saved as the default if doing this in developer mode?
974
Gtk::MessageDialog dialog(Utils::bold_message(_("Share On Network")), true, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_NONE);
975
dialog.set_secondary_text(_("Are you sure that you wish to allow other users on the network to use this database?"));
976
dialog.set_transient_for(*get_app_window());
977
dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
978
dialog.add_button(_("_Share"), Gtk::RESPONSE_OK);
980
const int response = dialog.run();
982
if(response == Gtk::RESPONSE_OK)
986
//Ask for a user/password if none is set:
987
const bool real_user_exists = Privs::get_developer_user_exists_with_password();
988
if(!real_user_exists)
990
//Ask for an initial user:
991
Glib::ustring user, password;
992
const bool initial_password_provided = connection_request_initial_password(user, password);
994
if(initial_password_provided)
995
added = add_user(user, password, GLOM_STANDARD_GROUP_NAME_DEVELOPER);
997
if(initial_password_provided && added)
999
//Use the new user/password from now on:
1000
ConnectionPool* connectionpool = ConnectionPool::get_instance();
1001
connectionpool->set_user(user);
1002
connectionpool->set_password(password);
1012
//Ask for the password of a developer user, to
1013
//a) Check that the user knows it, so he won't lose access.
1014
//b) Reconnect as that user so we can remove the default user.
1015
//TODO: Check that this user is a developer.
1016
bool database_not_found = false; //Ignored;
1017
const bool dev_password_known = connection_request_password_and_attempt(database_not_found, "" ,"", true /* alternative text */);
1018
if(!dev_password_known)
1025
if(change) //If nothing has gone wrong so far.
1027
//Remove the default no-password user, because that would be a security hole:
1028
//We do this after adding/using the non-default user, because we can't
1029
//remove a currently-used user.
1030
const bool default_user_exists = Privs::get_default_developer_user_exists();
1031
if(default_user_exists)
1033
//Force a reconnection with the new password:
1034
//ConnectionPool* connectionpool = ConnectionPool::get_instance();
1036
//Remove it, after stopping it from being the database owner:
1037
bool disabled = true;
1038
Glib::ustring default_password;
1039
const Glib::ustring default_user = Privs::get_default_developer_user_name(default_password);
1041
ConnectionPool* connectionpool = ConnectionPool::get_instance();
1042
const bool reowned = set_database_owner_user(connectionpool->get_user());
1043
bool removed = false;
1045
removed = remove_user(default_user);
1049
//This is a workaround.
1050
//Try to revoke it instead.
1051
//TODO: Discover how to make remove_user() succeed.
1052
disabled = disable_user(default_user);
1055
if(!reowned || !(removed || disabled))
1057
std::cerr << "Frame_Glom::on_menu_file_toggle_share(): Failed to reown and remove/revoke default user." << std::endl;
1072
//TODO: Warn about connected users if possible.
1073
Gtk::MessageDialog dialog(Utils::bold_message(_("Stop Sharing On Network")), true, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_NONE);
1074
dialog.set_secondary_text(_("Are you sure that you wish to prevent other users on the network from using this database?"));
1075
dialog.set_transient_for(*get_app_window());
1076
dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1077
dialog.add_button(_("_Stop Sharing"), Gtk::RESPONSE_OK);
1079
const int response = dialog.run();
1081
if(response == Gtk::RESPONSE_OK)
1085
//Make sure the default no-password user exists:
1086
const bool default_user_exists = Privs::get_default_developer_user_exists();
1087
if(!default_user_exists)
1090
Glib::ustring default_password;
1091
const Glib::ustring default_user = Privs::get_default_developer_user_name(default_password);
1093
const bool added = add_user(default_user, default_password, GLOM_STANDARD_GROUP_NAME_DEVELOPER);
1109
document->set_network_shared(shared);
1112
//Stop the self-hosted database server,
1113
//change its configuration,
1114
//and start it again:
1117
ConnectionPool* connectionpool = ConnectionPool::get_instance();
1118
sharedptr<SharedConnection> sharedconnection = connectionpool->connect();
1119
if(sharedconnection)
1121
sharedconnection->close();
1122
sharedconnection.clear();
1125
connectionpool->cleanup( sigc::mem_fun(*this, &Frame_Glom::on_connection_cleanup_progress) );
1127
if(m_dialog_progess_connection_cleanup)
1129
delete m_dialog_progess_connection_cleanup;
1130
m_dialog_progess_connection_cleanup = 0;
1133
connectionpool->set_network_shared(sigc::mem_fun(*this, &Frame_Glom::on_connection_startup_progress), shared);
1134
connectionpool->startup( sigc::mem_fun(*this, &Frame_Glom::on_connection_startup_progress) );
1135
connectionpool->set_ready_to_connect();
1137
if(m_dialog_progess_connection_startup)
1139
delete m_dialog_progess_connection_startup;
1140
m_dialog_progess_connection_startup = 0;
1145
App_Glom* pApp = dynamic_cast<App_Glom*>(get_app_window());
1148
pApp->update_network_shared_ui();
730
1151
#endif // !GLOM_ENABLE_CLIENT_ONLY
732
1153
void Frame_Glom::on_menu_file_print()
1565
1987
#endif // !GLOM_ENABLE_CLIENT_ONLY
1991
void setup_connection_pool_from_document(Document* document)
1993
ConnectionPool* connection_pool = ConnectionPool::get_instance();
1994
switch(document->get_hosting_mode())
1996
#ifdef GLOM_ENABLE_POSTGRESQL
1998
#ifndef GLOM_ENABLE_CLIENT_ONLY
1999
case Document::HOSTING_MODE_POSTGRES_SELF:
2001
ConnectionPoolBackends::PostgresSelfHosted* backend = new ConnectionPoolBackends::PostgresSelfHosted;
2002
backend->set_self_hosting_data_uri(document->get_connection_self_hosted_directory_uri());
2003
connection_pool->set_backend(std::auto_ptr<ConnectionPool::Backend>(backend));
2006
#endif //GLOM_ENABLE_CLIENT_ONLY
2008
case Document::HOSTING_MODE_POSTGRES_CENTRAL:
2010
ConnectionPoolBackends::PostgresCentralHosted* backend = new ConnectionPoolBackends::PostgresCentralHosted;
2011
backend->set_host(document->get_connection_server());
2012
backend->set_port(document->get_connection_port());
2013
backend->set_try_other_ports(document->get_connection_try_other_ports());
2014
connection_pool->set_backend(std::auto_ptr<ConnectionPool::Backend>(backend));
2017
#endif //GLOM_ENABLE_POSTGRESQL
2019
#ifdef GLOM_ENABLE_SQLITE
2020
case Document::HOSTING_MODE_SQLITE:
2022
ConnectionPoolBackends::Sqlite* backend = new ConnectionPoolBackends::Sqlite;
2023
backend->set_database_directory_uri(document->get_connection_self_hosted_directory_uri());
2024
connection_pool->set_backend(std::auto_ptr<ConnectionPool::Backend>(backend));
2027
#endif // GLOM_ENABLE_SQLITE
2030
//on_document_load() should have checked for this already, informing the user.
2031
std::cerr << "Glom: setup_connection_pool_from_document(): Unhandled hosting mode: " << document->get_hosting_mode() << std::endl;
2032
g_assert_not_reached();
2036
// Might be overwritten later when actually attempting a connection:
2037
connection_pool->set_user(document->get_connection_user());
2038
connection_pool->set_database(document->get_connection_database());
2040
connection_pool->set_ready_to_connect();
2044
#ifndef GLOM_ENABLE_CLIENT_ONLY
2045
void Frame_Glom::on_connection_initialize_progress()
2047
if(!m_dialog_progess_connection_initialize)
2048
m_dialog_progess_connection_initialize = Utils::get_and_show_pulse_dialog(_("Initializing Database Data"), get_app_window());
2050
m_dialog_progess_connection_initialize->pulse();
2052
#endif //GLOM_ENABLE_CLIENT_ONLY
2054
void Frame_Glom::on_connection_startup_progress()
2056
if(!m_dialog_progess_connection_startup)
2057
m_dialog_progess_connection_startup = Utils::get_and_show_pulse_dialog(_("Starting Database Server"), get_app_window());
2059
m_dialog_progess_connection_startup->pulse();
2062
void Frame_Glom::on_connection_cleanup_progress()
2064
if(!m_dialog_progess_connection_cleanup)
2065
m_dialog_progess_connection_cleanup = Utils::get_and_show_pulse_dialog(_("Stopping Database Server"), get_app_window());
2067
m_dialog_progess_connection_cleanup->pulse();
2070
bool Frame_Glom::handle_connection_initialize_errors(ConnectionPool::InitErrors error)
2072
Glib::ustring title;
2073
Glib::ustring message;
2075
if(error == ConnectionPool::Backend::INITERROR_NONE)
2077
else if(error == ConnectionPool::Backend::INITERROR_DIRECTORY_ALREADY_EXISTS)
2079
title = _("Directory Already Exists");
2080
message = _("There is an existing directory with the same name as the directory that should be created for the new database files. You should specify a different filename to use a new directory instead.");
2082
else if (error == ConnectionPool::Backend::INITERROR_COULD_NOT_CREATE_DIRECTORY)
2084
title = _("Could Not Create Directory");
2085
message = _("There was an error when attempting to create the directory for the new database files.");
2087
else if(error == ConnectionPool::Backend::INITERROR_COULD_NOT_START_SERVER)
2089
title = _("Could Not Start Database Server");
2090
message = _("There was an error when attempting to start the database server.");
2093
Utils::show_ok_dialog(title, message, *get_app_window(), Gtk::MESSAGE_ERROR);
2098
#ifndef GLOM_ENABLE_CLIENT_ONLY
2099
bool Frame_Glom::connection_request_initial_password(Glib::ustring& user, Glib::ustring& password)
2101
//Intialze output parameters:
2102
user = Glib::ustring();
2103
password = Glib::ustring();
2105
Document* document = dynamic_cast<Document*>(get_document());
2109
//This is only useful for self-hosted postgres:
2110
if(document->get_hosting_mode() != Document::HOSTING_MODE_POSTGRES_SELF)
2113
//Ask for a new username and password to specify when creating a new self-hosted database.
2114
Dialog_InitialPassword* dialog = 0;
2115
Glib::RefPtr<Gtk::Builder> refXml;
2117
#ifdef GLIBMM_EXCEPTIONS_ENABLED
2120
refXml = Gtk::Builder::create_from_file(Utils::get_glade_file_path("glom_developer.glade"), "dialog_initial_password");
2122
catch(const Gtk::BuilderError& ex)
2124
std::cerr << ex.what() << std::endl;
2128
std::auto_ptr<Gtk::BuilderError> error;
2129
refXml = Gtk::Builder::create_from_file(Utils::get_glade_file_path("glom_developer.glade"), "dialog_initial_password", error);
2132
std::cerr << error->what() << std::endl;
2135
#endif //GLIBMM_EXCEPTIONS_ENABLED
2137
refXml->get_widget_derived("dialog_initial_password", dialog);
2144
int response = Gtk::RESPONSE_OK;
2145
bool keep_trying = true;
2148
response = Utils::dialog_run_with_help(dialog, "dialog_new_self_hosted_connection");
2150
//Check the password is acceptable:
2151
if(response == Gtk::RESPONSE_OK)
2153
const bool password_ok = dialog->check_password();
2156
user = dialog->get_user();
2157
password = dialog->get_password();
2159
keep_trying = false; //Everything is OK.
2164
keep_trying = false; //The user cancelled.
2170
remove_view(dialog);
2174
return (response == Gtk::RESPONSE_OK);
1567
2177
bool Frame_Glom::connection_request_password_and_choose_new_database_name()
1569
Document_Glom* document = dynamic_cast<Document_Glom*>(get_document());
2179
Document* document = dynamic_cast<Document*>(get_document());
1573
#ifndef GLOM_ENABLE_CLIENT_ONLY
1574
//Give the ConnectionPool the self-hosted file path,
1575
//so that create_self_hosted() can succeed:
1576
2183
ConnectionPool* connection_pool = ConnectionPool::get_instance();
1578
// Client only mode does not support self hosting, so there is nothing to do.
1579
if(connection_pool && document && document->get_connection_is_self_hosted())
1581
// TODO: sleep, to give postgres time to start?
1582
connection_pool->set_self_hosted(document->get_connection_self_hosted_directory_uri());
1586
connection_pool->set_self_hosted(std::string());
1588
#endif // !GLOM_ENABLE_CLIENT_ONLY
2184
setup_connection_pool_from_document(document);
1590
2186
if(!m_pDialogConnection)
1593
2189
add_view(m_pDialogConnection); //Also a composite view.
1596
//Ask either for the existing username and password to use an existing database server,
1597
//or ask for a new username and password to specify when creating a new self-hosted database.
1599
#ifndef GLOM_ENABLE_CLIENT_ONLY
1600
if(document->get_connection_is_self_hosted())
2192
switch(document->get_hosting_mode())
1602
Dialog_NewSelfHostedConnection* dialog = 0;
1603
Glib::RefPtr<Gnome::Glade::Xml> refXml;
1605
#ifdef GLIBMM_EXCEPTIONS_ENABLED
1608
refXml = Gnome::Glade::Xml::create(Utils::get_glade_file_path("glom_developer.glade"), "dialog_new_self_hosted_connection");
1610
catch(const Gnome::Glade::XmlError& ex)
1612
std::cerr << ex.what() << std::endl;
1616
std::auto_ptr<Gnome::Glade::XmlError> error;
1617
refXml = Gnome::Glade::Xml::create(Utils::get_glade_file_path("glom_developer.glade"), "dialog_new_self_hosted_connection", error);
1620
std::cerr << error->what() << std::endl;
1625
refXml->get_widget_derived("dialog_new_self_hosted_connection", dialog);
1626
if(!dialog) return false;
1631
response = Gtk::RESPONSE_OK;
1632
bool keep_trying = true;
1635
response = Glom::Utils::dialog_run_with_help(dialog, "dialog_new_self_hosted_connection");
1637
//Check the password is acceptable:
1638
if(response == Gtk::RESPONSE_OK)
1640
const bool password_ok = dialog->check_password();
1643
keep_trying = false; //Everything is OK.
1647
keep_trying = false; //The user cancelled.
1653
// Create the requested self-hosting database:
1654
bool created = false;
1655
if(response == Gtk::RESPONSE_OK)
1657
created = dialog->create_self_hosted();
1660
const bool test = connection_pool->start_self_hosting(get_app_window());
2194
case Document::HOSTING_MODE_POSTGRES_SELF:
2196
Glib::ustring user, password;
2198
if(document->get_network_shared()) //Usually not the case when creating new documents.
2200
const bool test = connection_request_initial_password(user, password);
1664
// Store in document, so these values are actually used when connecting
1665
Document_Glom* document = get_document();
1668
document->set_connection_port(connection_pool->get_port());
1669
document->set_connection_try_other_ports(connection_pool->get_try_other_ports());
2206
//Use the default user because we are not network shared:
2207
user = Privs::get_default_developer_user_name(password);
2210
// Create the requested self-hosting database:
2212
//Set the connection details in the ConnectionPool singleton.
2213
//The ConnectionPool will now use these every time it tries to connect.
2214
connection_pool->set_user(user);
2215
connection_pool->set_password(password);
2217
const bool initialized = handle_connection_initialize_errors( connection_pool->initialize(
2218
sigc::mem_fun(*this, &Frame_Glom::on_connection_initialize_progress) ) );
2220
if(m_dialog_progess_connection_initialize)
2222
delete m_dialog_progess_connection_initialize;
2223
m_dialog_progess_connection_initialize = 0;
1675
//dialog->create_self_hosted() has already set enough information in the ConnectionPool to allow a connection so we can create the database in the new database cluster:
1677
2229
//Put the details into m_pDialogConnection too, because that's what we use to connect.
1678
2230
//This is a bit of a hack:
1679
2231
m_pDialogConnection->set_self_hosted_user_and_password(connection_pool->get_user(), connection_pool->get_password());
2233
//std::cout << "DEBUG: after connection_pool->initialize(). The database cluster should now exist." << std::endl;
1682
remove_view(dialog);
1684
//std::cout << "DEBUG: after dialog->create_self_hosted(). The database cluster should now exist." << std::endl;
1690
#endif // !GLOM_ENABLE_CLIENT_ONLY
1692
//Ask for connection details:
1693
m_pDialogConnection->load_from_document(); //Get good defaults.
1694
m_pDialogConnection->set_transient_for(*get_app_window());
1695
response = Glom::Utils::dialog_run_with_help(m_pDialogConnection, "dialog_connection");
1696
m_pDialogConnection->hide();
1699
if(response == Gtk::RESPONSE_OK)
1701
const Glib::ustring database_name = document->get_connection_database();
1703
//std::cout << "debug: database_name to create=" << database_name << std::endl;
1706
bool keep_trying = true;
1707
size_t extra_num = 0;
2238
#ifdef GLOM_ENABLE_POSTGRESQL
2239
case Document::HOSTING_MODE_POSTGRES_CENTRAL:
1710
Glib::ustring database_name_possible;
1712
database_name_possible = database_name; //Try the original name first.
2241
//Ask for connection details:
2242
m_pDialogConnection->load_from_document(); //Get good defaults.
2243
m_pDialogConnection->set_transient_for(*get_app_window());
2245
const int response = Glom::Utils::dialog_run_with_help(m_pDialogConnection, "dialog_connection");
2246
m_pDialogConnection->hide();
2248
if(response == Gtk::RESPONSE_OK)
2250
// We are not self-hosting, but we also call initialize() for
2251
// consistency (the backend will ignore it anyway).
2252
ConnectionPool::SlotProgress slot_ignored;
2253
if(!handle_connection_initialize_errors( connection_pool->initialize(slot_ignored)) )
2256
// Remember the user name in the document, to be able to open the
2257
// document again later:
2258
Glib::ustring username, password;
2259
m_pDialogConnection->get_username_and_password(username, password);
2260
document->set_connection_user(username);
1715
//Create a new database name by appending a number to the original name:
1716
char pchExtraNum[10];
1717
sprintf(pchExtraNum, "%d", extra_num);
1718
database_name_possible = (database_name + pchExtraNum);
2264
// The user cancelled
1722
m_pDialogConnection->set_database_name(database_name_possible);
1723
//std::cout << "debug: possible name=" << database_name_possible << std::endl;
2270
#endif //GLOM_ENABLE_POSTGRESQL
2271
#ifdef GLOM_ENABLE_SQLITE
2272
case Document::HOSTING_MODE_SQLITE:
2275
ConnectionPool::SlotProgress slot_ignored;
2276
if(!handle_connection_initialize_errors( connection_pool->initialize(slot_ignored)) )
2279
m_pDialogConnection->load_from_document(); //Get good defaults.
2280
// No authentication required
2284
#endif //GLOM_ENABLE_SQLITE
2286
g_assert_not_reached();
2290
// Do startup, such as starting the self-hosting database server
2291
if(!connection_pool->startup( sigc::mem_fun(*this, &Frame_Glom::on_connection_startup_progress) ))
2294
if(m_dialog_progess_connection_startup)
2296
delete m_dialog_progess_connection_startup;
2297
m_dialog_progess_connection_startup = 0;
2300
const Glib::ustring database_name = document->get_connection_database();
2302
//std::cout << "debug: database_name to create=" << database_name << std::endl;
2305
bool keep_trying = true;
2306
size_t extra_num = 0;
2309
Glib::ustring database_name_possible;
2311
database_name_possible = database_name; //Try the original name first.
2314
//Create a new database name by appending a number to the original name:
2315
Glib::ustring pchExtraNum = Glib::ustring::compose("%1", extra_num);
2316
database_name_possible = (database_name + pchExtraNum);
2320
m_pDialogConnection->set_database_name(database_name_possible);
2321
//std::cout << "debug: possible name=" << database_name_possible << std::endl;
1725
2323
#ifdef GLIBMM_EXCEPTIONS_ENABLED
2326
g_assert(m_pDialogConnection);
2327
sharedptr<SharedConnection> sharedconnection = m_pDialogConnection->connect_to_server_with_connection_settings();
2328
//If no exception was thrown then the database exists.
2329
//But we are looking for an unused database name, so we will try again.
2331
catch(const ExceptionConnection& ex)
2333
#else //GLIBMM_EXCEPTIONS_ENABLED
2334
std::auto_ptr<ExceptionConnection> error;
2335
g_assert(m_pDialogConnection);
2336
sharedptr<SharedConnection> sharedconnection = m_pDialogConnection->connect_to_server_with_connection_settings(error);
2339
const ExceptionConnection& ex = *error;
2340
#endif //GLIBMM_EXCEPTIONS_ENABLED
2341
//g_warning("Frame_Glom::connection_request_password_and_choose_new_database_name(): caught exception.");
2343
if(ex.get_failure_type() == ExceptionConnection::FAILURE_NO_SERVER)
1728
sharedptr<SharedConnection> sharedconnection = m_pDialogConnection->connect_to_server_with_connection_settings();
1729
//If no exception was thrown then the database exists.
1730
//But we are looking for an unused database name, so we will try again.
2345
//Warn the user, and let him try again:
2346
Utils::show_ok_dialog(_("Connection Failed"), _("Glom could not connect to the database server. Maybe you entered an incorrect user name or password, or maybe the postgres database server is not running."), *(get_app_window()), Gtk::MESSAGE_ERROR); //TODO: Add help button.
2347
keep_trying = false;
1732
catch(const ExceptionConnection& ex)
1735
std::auto_ptr<ExceptionConnection> error;
1736
sharedptr<SharedConnection> sharedconnection = m_pDialogConnection->connect_to_server_with_connection_settings(error);
1739
const ExceptionConnection& ex = *error;
1741
//g_warning("Frame_Glom::connection_request_password_and_choose_new_database_name(): caught exception.");
1743
if(ex.get_failure_type() == ExceptionConnection::FAILURE_NO_SERVER)
1745
//Warn the user, and let him try again:
1746
Utils::show_ok_dialog(_("Connection Failed"), _("Glom could not connect to the database server. Maybe you entered an incorrect user name or password, or maybe the postgres database server is not running."), *(get_app_window()), Gtk::MESSAGE_ERROR); //TODO: Add help button.
1751
std::cout << "Frame_Glom::connection_request_password_and_choose_new_database_name(): unused database name successfully found: " << database_name_possible << std::endl;
1752
//The connection to the server is OK, but the specified database does not exist.
1753
//That's good - we were looking for an unused database name.
1754
Document_Glom* document = get_document();
1757
std::cout << "debug: unused database name found: " << database_name_possible << std::endl;
1758
document->set_connection_database(database_name_possible);
1760
ConnectionPool* connection_pool = ConnectionPool::get_instance();
1762
document->set_connection_server(connection_pool->get_host());
2351
std::cout << "Frame_Glom::connection_request_password_and_choose_new_database_name(): unused database name successfully found: " << database_name_possible << std::endl;
2352
//The connection to the server is OK, but the specified database does not exist.
2353
//That's good - we were looking for an unused database name.
2355
std::cout << "debug: unused database name found: " << database_name_possible << std::endl;
2356
document->set_connection_database(database_name_possible);
2358
// Remember host and port if the document is not self hosted
2359
#ifdef GLOM_ENABLE_POSTGRESQL
2360
if(document->get_hosting_mode() == Document::HOSTING_MODE_POSTGRES_CENTRAL)
2362
ConnectionPool::Backend* backend = connection_pool->get_backend();
2363
ConnectionPoolBackends::PostgresCentralHosted* central = dynamic_cast<ConnectionPoolBackends::PostgresCentralHosted*>(backend);
2364
g_assert(central != NULL);
2366
document->set_connection_server(central->get_host());
2367
document->set_connection_port(central->get_port());
2368
document->set_connection_try_other_ports(false);
2371
// Remember port if the document is self-hosted, so that remote
2372
// connections to the database (usinc browse network) know what port to use.
2373
// TODO: There is already similar code in
2374
// connect_to_server_with_connection_settings, which is just not
2375
// executed because it failed with no database present. We should
2376
// somehow avoid this code duplication.
2377
else if(document->get_hosting_mode() == Document::HOSTING_MODE_POSTGRES_SELF)
2379
ConnectionPool::Backend* backend = connection_pool->get_backend();
2380
ConnectionPoolBackends::PostgresSelfHosted* self = dynamic_cast<ConnectionPoolBackends::PostgresSelfHosted*>(backend);
2381
g_assert(self != NULL);
2383
document->set_connection_port(self->get_port());
2384
document->set_connection_try_other_ports(false);
2387
#endif //GLOM_ENABLE_POSTGRESQL
1771
return false; //The user cancelled.
2394
cleanup_connection();
1776
#ifdef GLIBMM_EXCEPTIONS_ENABLED
1777
bool Frame_Glom::connection_request_password_and_attempt(const Glib::ustring known_username, const Glib::ustring& known_password)
1779
bool Frame_Glom::connection_request_password_and_attempt(const Glib::ustring known_username, const Glib::ustring& known_password, std::auto_ptr<ExceptionConnection>& error)
1782
if(!m_pDialogConnection)
2398
#endif //GLOM_ENABLE_CLIENT_ONLY
2400
void Frame_Glom::cleanup_connection()
2402
ConnectionPool* connection_pool = ConnectionPool::get_instance();
2403
connection_pool->cleanup( sigc::mem_fun(*this, &Frame_Glom::on_connection_cleanup_progress) );
2405
if(m_dialog_progess_connection_cleanup)
2407
delete m_dialog_progess_connection_cleanup;
2408
m_dialog_progess_connection_cleanup = 0;
2412
bool Frame_Glom::handle_request_password_connection_error(bool asked_for_password, const ExceptionConnection& ex, bool& database_not_found)
2414
g_warning("Frame_Glom::connection_request_password_and_attempt(): caught exception.");
2416
//Initialize input parameter:
2417
database_not_found = false;
2419
if(asked_for_password && ex.get_failure_type() == ExceptionConnection::FAILURE_NO_SERVER)
2421
//Warn the user, and let him try again:
2422
Utils::show_ok_dialog(_("Connection Failed"), _("Glom could not connect to the database server. Maybe you entered an incorrect user name or password, or maybe the postgres database server is not running."), *(get_app_window()), Gtk::MESSAGE_ERROR); //TODO: Add help button.
2425
else if(ex.get_failure_type() == ExceptionConnection::FAILURE_NO_DATABASE)
2427
cleanup_connection();
2429
//The connection to the server might be OK, but the specified database does not exist:
2430
//Or the connection failed when trying without a password.
2431
database_not_found = true; //Tell the caller about this error.
2436
std::cerr << "Frame_Glom::connection_request_password_and_attempt(): Unexpected exception: " << ex.what() << std::endl;
2437
cleanup_connection();
2442
bool Frame_Glom::connection_request_password_and_attempt(bool& database_not_found, const Glib::ustring known_username, const Glib::ustring& known_password, bool confirm_known_user)
2444
//Initialize output parameter:
2445
database_not_found = false;
2447
Document* document = dynamic_cast<Document*>(get_document());
2452
//Start a self-hosted server if necessary:
2453
ConnectionPool* connection_pool = ConnectionPool::get_instance();
2454
setup_connection_pool_from_document(document);
2455
if(!connection_pool->startup( sigc::mem_fun(*this, &Frame_Glom::on_connection_startup_progress) ))
2458
if(m_dialog_progess_connection_startup)
2460
delete m_dialog_progess_connection_startup;
2461
m_dialog_progess_connection_startup = 0;
2464
//Only ask for the password if we are shared on the network, or we are using a centrally hosted server.
2465
//Otherwise, no password question is necessary, due to how our self-hosted database server is configured.
2466
if(document->get_network_shared()
2467
|| document->get_hosting_mode() == Document::HOSTING_MODE_POSTGRES_CENTRAL)
2469
//We recreate the dialog each time to make sure it is clean of any changes:
2470
if(m_pDialogConnection)
2472
delete m_pDialogConnection;
2473
m_pDialogConnection = 0;
1784
2476
Utils::get_glade_widget_derived_with_warning("dialog_connection", m_pDialogConnection);
1785
2477
add_view(m_pDialogConnection); //Also a composite view.
1788
while(true) //Loop until a return
1790
//Ask for connection details:
1791
2479
m_pDialogConnection->load_from_document(); //Get good defaults.
1792
2480
m_pDialogConnection->set_transient_for(*get_app_window());
2482
//Show alternative text if necessary:
2483
if(confirm_known_user)
2484
m_pDialogConnection->set_confirm_existing_user_note();
1794
2486
if(!known_username.empty())
1795
2487
m_pDialogConnection->set_username(known_username);
1797
2489
if(!known_password.empty())
1798
2490
m_pDialogConnection->set_password(known_password);
2492
else if(m_pDialogConnection)
2494
//Later, if m_pDialogConnection is null then we assume we should use the known user/password:
2495
delete m_pDialogConnection;
2496
m_pDialogConnection = 0;
2500
//Ask for connection details:
2501
while(true) //Loop until a return
1800
2503
//Only show the dialog if we don't know the correct username/password yet:
1801
2504
int response = Gtk::RESPONSE_OK;
1802
if(known_username.empty() && known_password.empty())
2506
if(m_pDialogConnection)
1804
response = Glom::Utils::dialog_run_with_help(m_pDialogConnection, "dialog_connection");
1805
m_pDialogConnection->hide();
2508
response = Glom::Utils::dialog_run_with_help(m_pDialogConnection, "dialog_connection");
2509
m_pDialogConnection->hide();
2512
//Try to use the entered username/password:
1808
2513
if(response == Gtk::RESPONSE_OK)
1810
#ifdef GLIBMM_EXCEPTIONS_ENABLED
2515
sharedptr<SharedConnection> sharedconnection;
2517
//Ask for the user/password if necessary:
2518
//TODO: Remove any previous database setting?
2519
if(m_pDialogConnection)
1813
//TODO: Remove any previous database setting?
1814
sharedptr<SharedConnection> sharedconnection = m_pDialogConnection->connect_to_server_with_connection_settings();
1815
return true; //Succeeeded, because no exception was thrown.
2521
#ifdef GLIBMM_EXCEPTIONS_ENABLED
2524
sharedconnection = m_pDialogConnection->connect_to_server_with_connection_settings();
2525
// TODO: Save username in document?
2526
return true; //Succeeded, because no exception was thrown.
2528
catch(const ExceptionConnection& ex)
2530
if(!handle_request_password_connection_error(true, ex, database_not_found))
2533
#else //GLIBMM_EXCEPTIONS_ENABLED
2534
std::auto_ptr<ExceptionConnection> local_error;
2536
m_pDialogConnection->connect_to_server_with_connection_settings(local_error);
2537
if(!local_error.get())
2539
else if(!handle_request_password_connection_error(true, *local_error, database_not_found))
2541
#endif //GLIBMM_EXCEPTIONS_ENABLED
1817
catch(const ExceptionConnection& ex)
1820
std::auto_ptr<ExceptionConnection> local_error;
1821
sharedptr<SharedConnection> sharedconnection = m_pDialogConnection->connect_to_server_with_connection_settings(local_error);
1822
if(!local_error.get())
1826
const ExceptionConnection& ex = *local_error;
1828
g_warning("Frame_Glom::connection_request_password_and_attempt(): caught exception.");
1830
if(ex.get_failure_type() == ExceptionConnection::FAILURE_NO_SERVER)
1832
//Warn the user, and let him try again:
1833
Utils::show_ok_dialog(_("Connection Failed"), _("Glom could not connect to the database server. Maybe you entered an incorrect user name or password, or maybe the postgres database server is not running."), *(get_app_window()), Gtk::MESSAGE_ERROR); //TODO: Add help button.
1835
response = Glom::Utils::dialog_run_with_help(m_pDialogConnection, "dialog_connection");
1836
m_pDialogConnection->hide();
1837
if(response != Gtk::RESPONSE_OK)
1838
return false; //The user cancelled.
2545
//Use the known password:
2546
ConnectionPool* connectionpool = ConnectionPool::get_instance();
2547
connectionpool->set_user(known_username);
2548
connectionpool->set_password(known_password);
2550
#ifdef GLIBMM_EXCEPTIONS_ENABLED
2553
Base_DB::connect_to_server(get_app_window());
2554
return true; //Succeeded, because no exception was thrown.
2556
catch(const ExceptionConnection& ex)
2558
if(!handle_request_password_connection_error(false, ex, database_not_found))
2562
std::auto_ptr<ExceptionConnection> error;
2563
const bool connected = Base_DB::connect_to_server(get_app_window(), error);
2564
if(!connected || error.get())
2566
if(!handle_request_password_connection_error(false, *error, database_not_found))
1842
g_warning("Frame_Glom::connection_request_password_and_attempt(): rethrowing exception.");
1844
//The connection to the server is OK, but the specified database does not exist:
1845
#ifdef GLIBMM_EXCEPTIONS_ENABLED
1846
throw ex; //Pass it on for the caller to handle.
1848
error = local_error; //Pass it on for the caller to handle.
2578
cleanup_connection();
1857
2579
return false; //The user cancelled.