[glom] Base_DB: Move export_data_to_stream() to DbUtils.
- From: Murray Cumming <murrayc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glom] Base_DB: Move export_data_to_stream() to DbUtils.
- Date: Wed, 9 Mar 2016 22:40:25 +0000 (UTC)
commit add899732c2324187a5c00ff9bc187667ea54982
Author: Murray Cumming <murrayc murrayc com>
Date: Wed Mar 9 15:25:35 2016 +0100
Base_DB: Move export_data_to_stream() to DbUtils.
Also moving get_table_fields_to_show_for_sequence() to Utils.
This lets it be tested separately from the UI widgets.
glom/appwindow.cc | 3 +-
glom/base_db.cc | 180 -----------------------------
glom/base_db.h | 5 -
glom/frame_glom.cc | 144 +-----------------------
glom/frame_glom.h | 3 -
glom/libglom/db_utils_export.cc | 178 +++++++++++++++++++++++++++++
glom/libglom/db_utils_export.h | 42 +++++++
glom/libglom/filelist.am | 3 +
glom/libglom/utils.cc | 181 ++++++++++++++++++++++++++++++
glom/libglom/utils.h | 3 +
glom/mode_data/box_data.cc | 2 +-
glom/mode_data/box_data_portal.cc | 2 +-
glom/print_layout/canvas_print_layout.cc | 2 +-
13 files changed, 415 insertions(+), 333 deletions(-)
---
diff --git a/glom/appwindow.cc b/glom/appwindow.cc
index 186dcb3..1a43d33 100644
--- a/glom/appwindow.cc
+++ b/glom/appwindow.cc
@@ -35,6 +35,7 @@
#include <glom/glade_utils.h>
#include <libglom/algorithms_utils.h>
#include <libglom/db_utils.h>
+#include <libglom/db_utils_export.h>
#include <libglom/privs.h>
#include <glom/python_embed/python_ui_callbacks.h>
#include <glom/python_embed/glom_python.h>
@@ -2027,7 +2028,7 @@ void AppWindow::on_menu_file_save_as_example()
Document::type_example_rows example_rows;
FoundSet found_set;
found_set.m_table_name = table_name;
- m_pFrame->export_data_to_vector(example_rows, found_set, sequence);
+ DbUtils::export_data_to_vector(document, example_rows, found_set, sequence);
//std::cout << " debug after row_text=" << row_text << std::endl;
document->set_table_example_data(table_name, example_rows);
diff --git a/glom/base_db.cc b/glom/base_db.cc
index 2d0ca97..e176d79 100644
--- a/glom/base_db.cc
+++ b/glom/base_db.cc
@@ -504,31 +504,6 @@ std::shared_ptr<LayoutItem_Image> Base_DB::offer_imageobject(const std::shared_p
#endif // !GLOM_ENABLE_CLIENT_ONLY
-//static:
-bool Base_DB::get_field_primary_key_index_for_fields(const type_vec_fields& fields, guint& field_column)
-{
- //Initialize input parameter:
- field_column = 0;
-
- //TODO_performance: Cache the primary key?
- guint col = 0;
- guint cols_count = fields.size();
- while(col < cols_count)
- {
- if(fields[col]->get_primary_key())
- {
- field_column = col;
- return true;
- }
- else
- {
- ++col;
- }
- }
-
- return false; //Not found.
-}
-
std::shared_ptr<Field> Base_DB::get_field_primary_key_for_table(const Glib::ustring& table_name) const
{
const auto document = get_document();
@@ -551,161 +526,6 @@ std::shared_ptr<Field> Base_DB::get_field_primary_key_for_table(const Glib::ustr
return std::shared_ptr<Field>();
}
-void Base_DB::get_table_fields_to_show_for_sequence_add_group(const Glib::ustring& table_name, const
Privileges& table_privs, const type_vec_fields& all_db_fields, const std::shared_ptr<LayoutGroup>& group,
Base_DB::type_vecConstLayoutFields& vecFields) const
-{
- const auto document = std::dynamic_pointer_cast<const Document>(get_document());
-
- //g_warning("Box_Data::get_table_fields_to_show_for_sequence_add_group(): table_name=%s,
all_db_fields.size()=%d, group->name=%s", table_name.c_str(), all_db_fields.size(),
group->get_name().c_str());
-
- for(const auto& item : group->get_items())
- {
- auto item_field = std::dynamic_pointer_cast<LayoutItem_Field>(item);
- if(item_field)
- {
- //Get the field info:
- const auto field_name = item->get_name();
-
- if(item_field->get_has_relationship_name()) //If it's a field in a related table.
- {
- //TODO_Performance: get_fields_for_table_one_field() is probably very inefficient
- auto field = DbUtils::get_fields_for_table_one_field(document,
item_field->get_table_used(table_name), item->get_name());
- if(field)
- {
- auto layout_item = item_field;
- layout_item->set_full_field_details(field); //Fill in the full field information for later.
-
-
- //TODO_Performance: We do this once for each related field, even if there are 2 from the same
table:
- const auto privs_related = Privs::get_current_privs(item_field->get_table_used(table_name));
- layout_item->m_priv_view = privs_related.m_view;
- layout_item->m_priv_edit = privs_related.m_edit;
-
- vecFields.emplace_back(layout_item);
- }
- else
- {
- std::cerr << G_STRFUNC << ": related field not found: field=" << item->get_layout_display_name()
<< std::endl;
- }
- }
- else //It's a regular field in the table:
- {
- const auto iterFind = find_if_same_name(all_db_fields, field_name);
-
- //If the field does not exist anymore then we won't try to show it:
- if(iterFind != all_db_fields.end() )
- {
- auto layout_item = item_field;
- layout_item->set_full_field_details(*iterFind); //Fill the LayoutItem with the full field
information.
-
- //std::cout << "debug: " << G_STRFUNC << ": name=" << layout_item->get_name() << std::endl;
-
- //Prevent editing of the field if the user may not edit this table:
- layout_item->m_priv_view = table_privs.m_view;
- layout_item->m_priv_edit = table_privs.m_edit;
-
- vecFields.emplace_back(layout_item);
- }
- }
- }
- else
- {
- auto item_group = std::dynamic_pointer_cast<LayoutGroup>(item);
- if(item_group)
- {
- auto item_portal = std::dynamic_pointer_cast<LayoutItem_Portal>(item);
- if(!item_portal) //Do not recurse into portals. They are filled by means of a separate SQL query.
- {
- //Recurse:
- get_table_fields_to_show_for_sequence_add_group(table_name, table_privs, all_db_fields,
item_group, vecFields);
- }
- }
- }
- }
-
- if(vecFields.empty())
- {
- //std::cerr << G_STRFUNC << ": Returning empty list.\n";
- }
-}
-
-Base_DB::type_vecConstLayoutFields Base_DB::get_table_fields_to_show_for_sequence(const Glib::ustring&
table_name, const Document::type_list_layout_groups& mapGroupSequence) const
-{
- const auto pDoc = std::dynamic_pointer_cast<const Document>(get_document());
-
- //Get field definitions from the database, with corrections from the document:
- type_vec_fields all_fields = DbUtils::get_fields_for_table(pDoc, table_name);
-
- const auto table_privs = Privs::get_current_privs(table_name);
-
- //Get fields that the document says we should show:
- type_vecConstLayoutFields result;
- if(pDoc)
- {
- if(mapGroupSequence.empty())
- {
- //No field sequence has been saved in the document, so we use all fields by default, so we start with
something visible:
-
- //Start with the Primary Key as the first field:
- guint iPrimaryKey = 0;
- bool bPrimaryKeyFound = get_field_primary_key_index_for_fields(all_fields, iPrimaryKey);
- Glib::ustring primary_key_field_name;
- if(bPrimaryKeyFound)
- {
- auto layout_item = std::make_shared<LayoutItem_Field>();
- layout_item->set_full_field_details(all_fields[iPrimaryKey]);
-
- //Don't use thousands separators with ID numbers:
- layout_item->m_formatting.m_numeric_format.m_use_thousands_separator = false;
-
- layout_item->set_editable(true); //A sensible default.
-
- //Prevent editing of the field if the user may not edit this table:
- layout_item->m_priv_view = table_privs.m_view;
- layout_item->m_priv_edit = table_privs.m_edit;
-
- result.emplace_back(layout_item);
- }
-
- //Add the rest:
- for(const auto& field_info : all_fields)
- {
- if(field_info->get_name() != primary_key_field_name) //We already added the primary key.
- {
- auto layout_item = std::make_shared<LayoutItem_Field>();
- layout_item->set_full_field_details(field_info);
-
- layout_item->set_editable(true); //A sensible default.
-
- //Prevent editing of the field if the user may not edit this table:
- layout_item->m_priv_view = table_privs.m_view;
- layout_item->m_priv_edit = table_privs.m_edit;
-
- result.emplace_back(layout_item);
- }
- }
- }
- else
- {
- //We will show the fields that the document says we should:
- for(const auto& group : mapGroupSequence)
- {
- if(true) //!group->get_hidden())
- {
- //Get the fields:
- get_table_fields_to_show_for_sequence_add_group(table_name, table_privs, all_fields, group,
result);
- }
- }
- }
- }
-
- if(result.empty())
- {
- //std::cerr << G_STRFUNC << ": Returning empty list.\n";
- }
-
- return result;
-}
-
void Base_DB::calculate_field_in_all_records(const Glib::ustring& table_name, const std::shared_ptr<const
Field>& field)
{
auto primary_key = get_field_primary_key_for_table(table_name);
diff --git a/glom/base_db.h b/glom/base_db.h
index 078052a..6e85986 100644
--- a/glom/base_db.h
+++ b/glom/base_db.h
@@ -275,9 +275,6 @@ protected:
virtual void on_userlevel_changed(AppState::userlevels userlevel);
- type_vecConstLayoutFields get_table_fields_to_show_for_sequence(const Glib::ustring& table_name, const
Document::type_list_layout_groups& mapGroupSequence) const;
- void get_table_fields_to_show_for_sequence_add_group(const Glib::ustring& table_name, const Privileges&
table_privs, const type_vec_fields& all_db_fields, const std::shared_ptr<LayoutGroup>& group,
type_vecConstLayoutFields& vecFields) const;
-
bool get_primary_key_is_in_foundset(const FoundSet& found_set, const Gnome::Gda::Value& primary_key_value);
@@ -291,8 +288,6 @@ protected:
static Glib::RefPtr<Gnome::Gda::Connection> get_connection();
- static bool get_field_primary_key_index_for_fields(const type_vec_fields& fields, guint& field_column);
-
typedef std::vector<Glib::ustring> type_vec_strings;
static type_vec_strings util_vecStrings_from_Fields(const type_vec_fields& fields);
diff --git a/glom/frame_glom.cc b/glom/frame_glom.cc
index d8eb2ec..aa20cd8 100644
--- a/glom/frame_glom.cc
+++ b/glom/frame_glom.cc
@@ -26,6 +26,7 @@
#include <glom/import_csv/dialog_import_csv.h>
#include <glom/import_csv/dialog_import_csv_progress.h>
#include <libglom/appstate.h>
+#include <libglom/db_utils_export.h>
#include <libglom/connectionpool.h>
@@ -64,6 +65,7 @@
#include <glom/filechooser_export.h>
#include <libglom/privs.h>
#include <libglom/db_utils.h>
+#include <libglom/db_utils_export.h>
#include <sstream> //For stringstream.
#include <fstream>
#include <glibmm/i18n.h>
@@ -581,147 +583,7 @@ void Frame_Glom::on_menu_file_export()
return;
}
- export_data_to_stream(the_stream, found_set, mapGroupSequence);
-}
-
-//TODO: Reduce copy/pasting in these export_data_to_*() methods:
-void Frame_Glom::export_data_to_vector(Document::type_example_rows& the_vector, const FoundSet& found_set,
const Document::type_list_layout_groups& sequence)
-{
- type_vecConstLayoutFields fieldsSequence = get_table_fields_to_show_for_sequence(found_set.m_table_name,
sequence);
-
- if(fieldsSequence.empty())
- {
- std::cerr << G_STRFUNC << ": No fields in sequence.\n";
- return;
- }
-
- auto 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);
-
- //TODO: Lock the database (prevent changes) during export.
- auto result = DbUtils::query_execute_select(query);
-
- guint rows_count = 0;
- if(result)
- rows_count = result->get_n_rows();
-
- if(rows_count)
- {
- const guint columns_count = result->get_n_columns();
-
- for(guint row_index = 0; row_index < rows_count; ++row_index)
- {
- Document::type_row_data row_data;
-
- for(guint col_index = 0; col_index < columns_count; ++col_index)
- {
- const auto value = result->get_value_at(col_index, row_index);
-
- auto layout_item = fieldsSequence[col_index];
- //if(layout_item->m_field.get_glom_type() != Field::glom_field_type::IMAGE) //This is too much
data.
- //{
-
- //Output data in canonical SQL format, ignoring the user's locale, and ignoring the layout
formatting:
- row_data.emplace_back(value); //TODO_Performance: reserve the size.
-
- //if(layout_item->m_field.get_glom_type() == Field::glom_field_type::IMAGE) //This is too much
data.
- //{
- //std::cout << " field name=" << layout_item->get_name() << ", value=" <<
layout_item->m_field.sql(value) << std::endl;
- //}
- }
-
- //std::cout << " row_string=" << row_string << std::endl;
- the_vector.emplace_back(row_data); //TODO_Performance: Reserve the size.
- }
- }
-}
-
-void Frame_Glom::export_data_to_stream(std::ostream& the_stream, const FoundSet& found_set, const
Document::type_list_layout_groups& sequence)
-{
- type_vecConstLayoutFields fieldsSequence = get_table_fields_to_show_for_sequence(found_set.m_table_name,
sequence);
-
- if(fieldsSequence.empty())
- {
- std::cerr << G_STRFUNC << ": No fields in sequence.\n";
- return;
- }
-
- auto 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);
-
- //TODO: Lock the database (prevent changes) during export.
- auto result = DbUtils::query_execute_select(query);
-
- guint rows_count = 0;
- if(result)
- rows_count = result->get_n_rows();
-
- if(rows_count)
- {
- const guint columns_count = result->get_n_columns();
-
- for(guint row_index = 0; row_index < rows_count; ++row_index)
- {
- std::string row_string;
-
- for(guint col_index = 0; col_index < columns_count; ++col_index)
- {
- const auto value = result->get_value_at(col_index, row_index);
-
- auto layout_item = fieldsSequence[col_index];
- //if(layout_item->m_field.get_glom_type() != Field::glom_field_type::IMAGE) //This is too much
data.
- //{
- if(!row_string.empty())
- row_string += ",";
-
- //Output data in canonical SQL format, ignoring the user's locale, and ignoring the layout
formatting:
- auto field = layout_item->get_full_field_details();
- if(!field)
- {
- std::cerr << G_STRFUNC << ": A field was null.\n";
- return;
- }
-
- const auto field_text = field->to_file_format(value);
-
- if(layout_item->get_glom_type() == Field::glom_field_type::IMAGE) //This is too much data.
- {
- // 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";
- size_t pos = field_text.find_first_of(newline_to_find);
- if(pos != std::string::npos)
- {
- std::cerr << G_STRFUNC << ": export: binary data field text contains an unexpected newline:
" << field_text << std::endl;
- continue;
- }
-
- const char* quote_to_find = "\"";
- pos = field_text.find_first_of(quote_to_find);
- if(pos != std::string::npos)
- {
- std::cerr << G_STRFUNC << ": export: binary data field text contains an unexpected quote: "
<< field_text << std::endl;
- continue;
- }
- }
-
- if(layout_item->get_glom_type() == Field::glom_field_type::TEXT)
- {
- //The CSV RFC says text may be quoted and should be if it has newlines:
- //TODO: Escape the 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;
- //}
- }
-
- //std::cout << " row_string=" << row_string << std::endl;
- the_stream << row_string << std::endl;
- }
- }
+ DbUtils::export_data_to_stream(document, the_stream, found_set, mapGroupSequence);
}
void Frame_Glom::on_menu_file_import()
diff --git a/glom/frame_glom.h b/glom/frame_glom.h
index dccd5c3..5fc72a6 100644
--- a/glom/frame_glom.h
+++ b/glom/frame_glom.h
@@ -171,9 +171,6 @@ public:
void set_enable_layout_drag_and_drop(bool enable = true);
#endif // !GLOM_ENABLE_CLIENT_ONLY
- void export_data_to_vector(Document::type_example_rows& the_vector, const FoundSet& found_set, const
Document::type_list_layout_groups& sequence);
- void export_data_to_stream(std::ostream& the_stream, const FoundSet& found_set, const
Document::type_list_layout_groups& sequence);
-
/** Show the table again. For instance, if the document has changed, or we want to display it differently.
*/
void show_table_refresh();
diff --git a/glom/libglom/db_utils_export.cc b/glom/libglom/db_utils_export.cc
new file mode 100644
index 0000000..f281ca7
--- /dev/null
+++ b/glom/libglom/db_utils_export.cc
@@ -0,0 +1,178 @@
+/* Glom
+ *
+ * Copyright (C) 2001-2010 Murray Cumming
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ */
+
+
+#include <libglom/db_utils_export.h>
+#include <libglom/db_utils.h>
+#include <libglom/utils.h>
+#include <libglom/algorithms_utils.h>
+#include <libgdamm/metastore.h>
+#include <iostream>
+
+namespace Glom
+{
+
+namespace DbUtils
+{
+
+
+//TODO: Reduce copy/pasting in these export_data_to_*() methods:
+void export_data_to_vector(const std::shared_ptr<Document>& document, Document::type_example_rows&
the_vector, const FoundSet& found_set, const Document::type_list_layout_groups& sequence)
+{
+ auto fieldsSequence = Utils::get_table_fields_to_show_for_sequence(document, found_set.m_table_name,
sequence);
+
+ if(fieldsSequence.empty())
+ {
+ std::cerr << G_STRFUNC << ": No fields in sequence.\n";
+ return;
+ }
+
+ auto 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);
+
+ //TODO: Lock the database (prevent changes) during export.
+ auto result = DbUtils::query_execute_select(query);
+
+ guint rows_count = 0;
+ if(result)
+ rows_count = result->get_n_rows();
+
+ if(rows_count)
+ {
+ const guint columns_count = result->get_n_columns();
+
+ for(guint row_index = 0; row_index < rows_count; ++row_index)
+ {
+ Document::type_row_data row_data;
+
+ for(guint col_index = 0; col_index < columns_count; ++col_index)
+ {
+ const auto value = result->get_value_at(col_index, row_index);
+
+ auto layout_item = fieldsSequence[col_index];
+ //if(layout_item->m_field.get_glom_type() != Field::glom_field_type::IMAGE) //This is too much
data.
+ //{
+
+ //Output data in canonical SQL format, ignoring the user's locale, and ignoring the layout
formatting:
+ row_data.emplace_back(value); //TODO_Performance: reserve the size.
+
+ //if(layout_item->m_field.get_glom_type() == Field::glom_field_type::IMAGE) //This is too much
data.
+ //{
+ //std::cout << " field name=" << layout_item->get_name() << ", value=" <<
layout_item->m_field.sql(value) << std::endl;
+ //}
+ }
+
+ //std::cout << " row_string=" << row_string << std::endl;
+ the_vector.emplace_back(row_data); //TODO_Performance: Reserve the size.
+ }
+ }
+}
+
+void export_data_to_stream(const std::shared_ptr<Document>& document, std::ostream& the_stream, const
FoundSet& found_set, const Document::type_list_layout_groups& sequence)
+{
+ auto fieldsSequence = Utils::get_table_fields_to_show_for_sequence(document, found_set.m_table_name,
sequence);
+
+ if(fieldsSequence.empty())
+ {
+ std::cerr << G_STRFUNC << ": No fields in sequence.\n";
+ return;
+ }
+
+ auto 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);
+
+ //TODO: Lock the database (prevent changes) during export.
+ auto result = DbUtils::query_execute_select(query);
+
+ guint rows_count = 0;
+ if(result)
+ rows_count = result->get_n_rows();
+
+ if(rows_count)
+ {
+ const guint columns_count = result->get_n_columns();
+
+ for(guint row_index = 0; row_index < rows_count; ++row_index)
+ {
+ std::string row_string;
+
+ for(guint col_index = 0; col_index < columns_count; ++col_index)
+ {
+ const auto value = result->get_value_at(col_index, row_index);
+
+ auto layout_item = fieldsSequence[col_index];
+ //if(layout_item->m_field.get_glom_type() != Field::glom_field_type::IMAGE) //This is too much
data.
+ //{
+ if(!row_string.empty())
+ row_string += ",";
+
+ //Output data in canonical SQL format, ignoring the user's locale, and ignoring the layout
formatting:
+ auto field = layout_item->get_full_field_details();
+ if(!field)
+ {
+ std::cerr << G_STRFUNC << ": A field was null.\n";
+ return;
+ }
+
+ const auto field_text = field->to_file_format(value);
+
+ if(layout_item->get_glom_type() == Field::glom_field_type::IMAGE) //This is too much data.
+ {
+ // 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";
+ size_t pos = field_text.find_first_of(newline_to_find);
+ if(pos != std::string::npos)
+ {
+ std::cerr << G_STRFUNC << ": export: binary data field text contains an unexpected newline:
" << field_text << std::endl;
+ continue;
+ }
+
+ const char* quote_to_find = "\"";
+ pos = field_text.find_first_of(quote_to_find);
+ if(pos != std::string::npos)
+ {
+ std::cerr << G_STRFUNC << ": export: binary data field text contains an unexpected quote: "
<< field_text << std::endl;
+ continue;
+ }
+ }
+
+ if(layout_item->get_glom_type() == Field::glom_field_type::TEXT)
+ {
+ //The CSV RFC says text may be quoted and should be if it has newlines:
+ //TODO: Escape the 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;
+ //}
+ }
+
+ //std::cout << " row_string=" << row_string << std::endl;
+ the_stream << row_string << std::endl;
+ }
+ }
+}
+
+} //namespace DbUtils
+
+} //namespace Glom
diff --git a/glom/libglom/db_utils_export.h b/glom/libglom/db_utils_export.h
new file mode 100644
index 0000000..77ccebe
--- /dev/null
+++ b/glom/libglom/db_utils_export.h
@@ -0,0 +1,42 @@
+/* Glom
+ *
+ * Copyright (C) 2001-2016 Murray Cumming
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ */
+
+#ifndef GLOM_DB_UTILS_EXPORT_H
+#define GLOM_DB_UTILS_EXPORT_H
+
+#include <libglom/document/document.h>
+#include <libglom/data_structure/system_prefs.h>
+#include <memory> //For shared_ptr<>.
+
+namespace Glom
+{
+
+namespace DbUtils
+{
+
+void export_data_to_vector(const std::shared_ptr<Document>& document, Document::type_example_rows&
the_vector, const FoundSet& found_set, const Document::type_list_layout_groups& sequence);
+
+void export_data_to_stream(const std::shared_ptr<Document>& document, std::ostream& the_stream, const
FoundSet& found_set, const Document::type_list_layout_groups& sequence);
+
+} //namespace DbUtils
+
+} //namespace Glom
+
+#endif //GLOM_DB_UTILS_EXPORT_H
diff --git a/glom/libglom/filelist.am b/glom/libglom/filelist.am
index b3a9828..30013cd 100644
--- a/glom/libglom/filelist.am
+++ b/glom/libglom/filelist.am
@@ -26,6 +26,7 @@ libglom_toplevel_headers = \
glom/libglom/standard_table_prefs_fields.h \
glom/libglom/utils.h \
glom/libglom/db_utils.h \
+ glom/libglom/db_utils_export.h \
glom/libglom/report_builder.h \
glom/libglom/translations_po.h
@@ -105,6 +106,8 @@ libglom_sources = \
glom/libglom/connectionpool.h \
glom/libglom/db_utils.cc \
glom/libglom/db_utils.h \
+ glom/libglom/db_utils_export.cc \
+ glom/libglom/db_utils_export.h \
glom/libglom/glom_postgres.cc \
glom/libglom/glom_postgres.h \
glom/libglom/init.cc \
diff --git a/glom/libglom/utils.cc b/glom/libglom/utils.cc
index 1bdbcb4..69a4760 100644
--- a/glom/libglom/utils.cc
+++ b/glom/libglom/utils.cc
@@ -21,6 +21,8 @@
#include <libglom/libglom_config.h>
#include <libglom/utils.h>
+#include <libglom/db_utils.h>
+#include <libglom/privs.h>
#include <libglom/connectionpool.h>
#include <libglom/data_structure/layout/report_parts/layoutitem_fieldsummary.h>
#include <libglom/data_structure/glomconversions.h>
@@ -1516,6 +1518,185 @@ LayoutGroup::type_list_items Utils::get_layout_items_plus_primary_key(const Layo
return items_plus_pk;
}
+namespace {
+
+static bool get_field_primary_key_index_for_fields(const Utils::type_vec_fields& fields, guint& field_column)
+{
+ //Initialize input parameter:
+ field_column = 0;
+
+ //TODO_performance: Cache the primary key?
+ guint col = 0;
+ guint cols_count = fields.size();
+ while(col < cols_count)
+ {
+ if(fields[col]->get_primary_key())
+ {
+ field_column = col;
+ return true;
+ }
+ else
+ {
+ ++col;
+ }
+ }
+
+ return false; //Not found.
+}
+
+static void get_table_fields_to_show_for_sequence_add_group(const std::shared_ptr<const Document>& document,
const Glib::ustring& table_name, const Privileges& table_privs, const Utils::type_vec_fields& all_db_fields,
const std::shared_ptr<LayoutGroup>& group, Utils::type_vecConstLayoutFields& vecFields)
+{
+ //g_warning("Box_Data::get_table_fields_to_show_for_sequence_add_group(): table_name=%s,
all_db_fields.size()=%d, group->name=%s", table_name.c_str(), all_db_fields.size(),
group->get_name().c_str());
+
+ for(const auto& item : group->get_items())
+ {
+ auto item_field = std::dynamic_pointer_cast<LayoutItem_Field>(item);
+ if(item_field)
+ {
+ //Get the field info:
+ const auto field_name = item->get_name();
+
+ if(item_field->get_has_relationship_name()) //If it's a field in a related table.
+ {
+ //TODO_Performance: get_fields_for_table_one_field() is probably very inefficient
+ auto field = DbUtils::get_fields_for_table_one_field(document,
item_field->get_table_used(table_name), item->get_name());
+ if(field)
+ {
+ auto layout_item = item_field;
+ layout_item->set_full_field_details(field); //Fill in the full field information for later.
+
+
+ //TODO_Performance: We do this once for each related field, even if there are 2 from the same
table:
+ const auto privs_related = Privs::get_current_privs(item_field->get_table_used(table_name));
+ layout_item->m_priv_view = privs_related.m_view;
+ layout_item->m_priv_edit = privs_related.m_edit;
+
+ vecFields.emplace_back(layout_item);
+ }
+ else
+ {
+ std::cerr << G_STRFUNC << ": related field not found: field=" << item->get_layout_display_name()
<< std::endl;
+ }
+ }
+ else //It's a regular field in the table:
+ {
+ const auto iterFind = find_if_same_name(all_db_fields, field_name);
+
+ //If the field does not exist anymore then we won't try to show it:
+ if(iterFind != all_db_fields.end() )
+ {
+ auto layout_item = item_field;
+ layout_item->set_full_field_details(*iterFind); //Fill the LayoutItem with the full field
information.
+
+ //std::cout << "debug: " << G_STRFUNC << ": name=" << layout_item->get_name() << std::endl;
+
+ //Prevent editing of the field if the user may not edit this table:
+ layout_item->m_priv_view = table_privs.m_view;
+ layout_item->m_priv_edit = table_privs.m_edit;
+
+ vecFields.emplace_back(layout_item);
+ }
+ }
+ }
+ else
+ {
+ auto item_group = std::dynamic_pointer_cast<LayoutGroup>(item);
+ if(item_group)
+ {
+ auto item_portal = std::dynamic_pointer_cast<LayoutItem_Portal>(item);
+ if(!item_portal) //Do not recurse into portals. They are filled by means of a separate SQL query.
+ {
+ //Recurse:
+ get_table_fields_to_show_for_sequence_add_group(document, table_name, table_privs, all_db_fields,
item_group, vecFields);
+ }
+ }
+ }
+ }
+
+ if(vecFields.empty())
+ {
+ //std::cerr << G_STRFUNC << ": Returning empty list.\n";
+ }
+}
+
+} //anonymous namespace
+
+Utils::type_vecConstLayoutFields Utils::get_table_fields_to_show_for_sequence(const std::shared_ptr<const
Document>& document, const Glib::ustring& table_name, const Document::type_list_layout_groups&
mapGroupSequence)
+{
+ //Get field definitions from the database, with corrections from the document:
+ auto all_fields = DbUtils::get_fields_for_table(document, table_name);
+
+ const auto table_privs = Privs::get_current_privs(table_name);
+
+ //Get fields that the document says we should show:
+ type_vecConstLayoutFields result;
+ if(document)
+ {
+ if(mapGroupSequence.empty())
+ {
+ //No field sequence has been saved in the document, so we use all fields by default, so we start with
something visible:
+
+ //Start with the Primary Key as the first field:
+ guint iPrimaryKey = 0;
+ bool bPrimaryKeyFound = get_field_primary_key_index_for_fields(all_fields, iPrimaryKey);
+ Glib::ustring primary_key_field_name;
+ if(bPrimaryKeyFound)
+ {
+ auto layout_item = std::make_shared<LayoutItem_Field>();
+ layout_item->set_full_field_details(all_fields[iPrimaryKey]);
+
+ //Don't use thousands separators with ID numbers:
+ layout_item->m_formatting.m_numeric_format.m_use_thousands_separator = false;
+
+ layout_item->set_editable(true); //A sensible default.
+
+ //Prevent editing of the field if the user may not edit this table:
+ layout_item->m_priv_view = table_privs.m_view;
+ layout_item->m_priv_edit = table_privs.m_edit;
+
+ result.emplace_back(layout_item);
+ }
+
+ //Add the rest:
+ for(const auto& field_info : all_fields)
+ {
+ if(field_info->get_name() != primary_key_field_name) //We already added the primary key.
+ {
+ auto layout_item = std::make_shared<LayoutItem_Field>();
+ layout_item->set_full_field_details(field_info);
+
+ layout_item->set_editable(true); //A sensible default.
+
+ //Prevent editing of the field if the user may not edit this table:
+ layout_item->m_priv_view = table_privs.m_view;
+ layout_item->m_priv_edit = table_privs.m_edit;
+
+ result.emplace_back(layout_item);
+ }
+ }
+ }
+ else
+ {
+ //We will show the fields that the document says we should:
+ for(const auto& group : mapGroupSequence)
+ {
+ if(true) //!group->get_hidden())
+ {
+ //Get the fields:
+ get_table_fields_to_show_for_sequence_add_group(document, table_name, table_privs, all_fields,
group, result);
+ }
+ }
+ }
+ }
+
+ if(result.empty())
+ {
+ //std::cerr << G_STRFUNC << ": Returning empty list.\n";
+ }
+
+ return result;
+}
+
bool Utils::script_check_for_pygtk2(const Glib::ustring& script)
{
//There is probably other code that this will not catch,
diff --git a/glom/libglom/utils.h b/glom/libglom/utils.h
index f4420c3..657ddb2 100644
--- a/glom/libglom/utils.h
+++ b/glom/libglom/utils.h
@@ -51,6 +51,7 @@ Glib::ustring string_clean_for_xml(const Glib::ustring& src);
//typedef Base_DB::type_vecLayoutFields type_vecLayoutFields;
typedef std::vector< std::shared_ptr<LayoutItem_Field> > type_vecLayoutFields;
typedef std::vector< std::shared_ptr<const LayoutItem_Field> > type_vecConstLayoutFields;
+typedef std::vector< std::shared_ptr<Field> > type_vec_fields;
//TODO: Move these to their own file:
@@ -231,6 +232,8 @@ LayoutGroup::type_list_const_items get_layout_items_plus_primary_key(const Layou
*/
LayoutGroup::type_list_items get_layout_items_plus_primary_key(const LayoutGroup::type_list_items& items,
const std::shared_ptr<const Document>& document, const Glib::ustring& table_name);
+type_vecConstLayoutFields get_table_fields_to_show_for_sequence(const std::shared_ptr<const Document>&
document, const Glib::ustring& table_name, const Document::type_list_layout_groups& mapGroupSequence);
+
std::string get_temp_file_path(const std::string& prefix = std::string(), const std::string& extension =
std::string());
Glib::ustring get_temp_file_uri(const std::string& prefix = std::string(), const std::string& extension =
std::string());
diff --git a/glom/mode_data/box_data.cc b/glom/mode_data/box_data.cc
index 9682634..a085e29 100644
--- a/glom/mode_data/box_data.cc
+++ b/glom/mode_data/box_data.cc
@@ -242,7 +242,7 @@ Box_Data::type_vecConstLayoutFields Box_Data::get_table_fields_to_show(const Gli
if(pDoc)
{
Document::type_list_layout_groups mapGroupSequence =
pDoc->get_data_layout_groups_plus_new_fields(m_layout_name, table_name, m_layout_platform);
- return get_table_fields_to_show_for_sequence(table_name, mapGroupSequence);
+ return Utils::get_table_fields_to_show_for_sequence(pDoc, table_name, mapGroupSequence);
}
else
return type_vecConstLayoutFields();
diff --git a/glom/mode_data/box_data_portal.cc b/glom/mode_data/box_data_portal.cc
index 3b96f44..6c095c8 100644
--- a/glom/mode_data/box_data_portal.cc
+++ b/glom/mode_data/box_data_portal.cc
@@ -190,7 +190,7 @@ Box_Data_Portal::type_vecConstLayoutFields Box_Data_Portal::get_fields_to_show()
auto relationship = m_portal->get_relationship();
if(relationship)
{
- type_vecConstLayoutFields result =
get_table_fields_to_show_for_sequence(m_portal->get_table_used(Glib::ustring() /* not relevant */),
mapGroups);
+ auto result = Utils::get_table_fields_to_show_for_sequence(document,
m_portal->get_table_used(Glib::ustring() /* not relevant */), mapGroups);
//If the relationship does not allow editing, then mark all these fields as non-editable:
//TODO: Prevent this in some other way:
diff --git a/glom/print_layout/canvas_print_layout.cc b/glom/print_layout/canvas_print_layout.cc
index 547892f..654b722 100644
--- a/glom/print_layout/canvas_print_layout.cc
+++ b/glom/print_layout/canvas_print_layout.cc
@@ -1067,7 +1067,7 @@ Base_DB::type_vecConstLayoutFields Canvas_PrintLayout::get_portal_fields_to_show
auto relationship = portal->get_relationship();
if(relationship)
{
- type_vecConstLayoutFields result =
get_table_fields_to_show_for_sequence(portal->get_table_used(Glib::ustring() /* not relevant */), mapGroups);
+ auto result = Utils::get_table_fields_to_show_for_sequence(document,
portal->get_table_used(Glib::ustring() /* not relevant */), mapGroups);
//If the relationship does not allow editing, then mark all these fields as non-editable:
/* TODO: Find a better way to do this.
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]