Commit d136618e authored by Murray Cumming's avatar Murray Cumming
Browse files

utils: Move some functions into layout_utils.

parent cd91632e
......@@ -252,6 +252,8 @@ set(SOURCE_FILES
glom/libglom/standard_table_prefs_fields.h
glom/libglom/translations_po.cc
glom/libglom/translations_po.h
glom/libglom/layout_utils.cc
glom/libglom/layout_utils.h
glom/libglom/file_utils.cc
glom/libglom/file_utils.h
glom/libglom/sql_utils.cc
......
......@@ -21,6 +21,7 @@
#include <libglom/db_utils_export.h>
#include <libglom/db_utils.h>
#include <libglom/layout_utils.h>
#include <libglom/utils.h>
#include <libglom/sql_utils.h>
#include <libglom/algorithms_utils.h>
......
......@@ -27,6 +27,7 @@ libglom_toplevel_headers = \
glom/libglom/utils.h \
glom/libglom/db_utils.h \
glom/libglom/db_utils_export.h \
glom/libglom/layout_utils.h \
glom/libglom/sql_utils.h \
glom/libglom/report_builder.h \
glom/libglom/translations_po.h
......@@ -111,6 +112,8 @@ libglom_sources = \
glom/libglom/db_utils_export.h \
glom/libglom/file_utils.cc \
glom/libglom/file_utils.h \
glom/libglom/layout_utils.cc \
glom/libglom/layout_utils.h \
glom/libglom/glom_postgres.cc \
glom/libglom/glom_postgres.h \
glom/libglom/init.cc \
......
/* 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.
*/
#include <libglom/layout_utils.h>
#include <libglom/db_utils.h>
#include <libglom/layout_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>
#include <libglom/string_utils.h>
#include <giomm/file.h>
#include <giomm/resource.h>
#include <glibmm/convert.h>
#include <glibmm/fileutils.h>
#include <glibmm/miscutils.h>
#include <glibmm/i18n.h>
#include <string.h> // for strchr
#include <sstream> //For stringstream
#include <iostream>
#include "utils.h"
namespace Glom
{
Glib::ustring Utils::get_list_of_layout_items_for_display(const LayoutGroup::type_list_items& list_layout_fields)
{
Glib::ustring result;
for(const auto& item : list_layout_fields)
{
if(item)
{
if(!result.empty())
result += ", ";
result += item->get_layout_display_name();
}
}
return result;
}
Glib::ustring Utils::get_list_of_layout_items_for_display(const std::shared_ptr<const LayoutGroup>& layout_group)
{
if(layout_group)
return get_list_of_layout_items_for_display(layout_group->m_list_items);
else
return Glib::ustring();
}
Glib::ustring Utils::get_list_of_sort_fields_for_display(const Formatting::type_list_sort_fields& sort_fields)
{
Glib::ustring text;
for(const auto& the_pair : sort_fields)
{
const auto item = the_pair.first;
if(!item)
continue;
if(!text.empty())
text += ", ";
text += item->get_layout_display_name();
//TODO: Show Ascending/Descending?
}
return text;
}
LayoutGroup::type_list_const_items Utils::get_layout_items_plus_primary_key(const LayoutGroup::type_list_const_items& items, const std::shared_ptr<const Document>& document, const Glib::ustring& table_name)
{
if(!document)
{
std::cerr << G_STRFUNC << ": document was null.\n";
return items;
}
const auto field_primary_key = document->get_field_primary_key(table_name);
if(!field_primary_key)
{
std::cerr << G_STRFUNC << ": Could not find the primary key.\n";
return items;
}
auto pk_layout_item = std::make_shared<LayoutItem_Field>();
pk_layout_item->set_hidden();
pk_layout_item->set_full_field_details(field_primary_key);
if(find_if_layout_item_field_is_same_field_exists(items, pk_layout_item))
return items; //It is already in the list:
LayoutGroup::type_list_const_items items_plus_pk = items;
items_plus_pk.emplace_back(pk_layout_item);
return items_plus_pk;
}
//TODO: Avoid the horrible code duplication with the const version.
LayoutGroup::type_list_items Utils::get_layout_items_plus_primary_key(const LayoutGroup::type_list_items& items, const std::shared_ptr<const Document>& document, const Glib::ustring& table_name)
{
if(!document)
{
std::cerr << G_STRFUNC << ": document was null.\n";
return items;
}
const auto field_primary_key = document->get_field_primary_key(table_name);
if(!field_primary_key)
{
std::cerr << G_STRFUNC << ": Could not find the primary key.\n";
return items;
}
auto pk_layout_item = std::make_shared<LayoutItem_Field>();
pk_layout_item->set_hidden();
pk_layout_item->set_full_field_details(field_primary_key);
if(find_if_layout_item_field_is_same_field_exists(items, pk_layout_item))
return items; //It is already in the list:
LayoutGroup::type_list_items items_plus_pk = items;
items_plus_pk.emplace_back(pk_layout_item);
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;
}
} //namespace Glom
/* 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_LAYOUT_UTILS_H
#define GLOM_LAYOUT_UTILS_H
#include <libglom/document/document.h>
#include <libglom/data_structure/layout/layoutitem_field.h>
#include <libglom/algorithms_utils.h>
namespace Glom
{
namespace Utils
{
typedef std::vector< std::shared_ptr<const LayoutItem_Field> > type_vecConstLayoutFields;
typedef std::vector< std::shared_ptr<Field> > type_vec_fields;
/** Get a string to display to the user, as a representation of a list of layout items.
*/
Glib::ustring get_list_of_layout_items_for_display(const LayoutGroup::type_list_items& list_layout_fields);
/** Get a string to display to the user, as a representation of a list of layout items.
*/
Glib::ustring get_list_of_layout_items_for_display(const std::shared_ptr<const LayoutGroup>& layout_group);
/** Get a string to display to the user, as a representation of a sort order
*/
Glib::ustring get_list_of_sort_fields_for_display(const Formatting::type_list_sort_fields& sort_fields);
/** This returns the provided list of layout items,
* plus the primary key, if the primary key is not already present in the list
*/
LayoutGroup::type_list_const_items get_layout_items_plus_primary_key(const LayoutGroup::type_list_const_items& items, const std::shared_ptr<const Document>& document, const Glib::ustring& table_name);
//TODO: Avoid the overload just for constness.
/** This returns the provided list of layout items,
* plus the primary key, if the primary key is not already present in the list
*/
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);
/**
* Find the element in the container which is a LayoutItem_Field which refers
* to the same field, without comparing irrelevant stuff such as formatting.
* This assumes that the element is a shared_ptr<>.
*/
template
<typename T_Container>
bool find_if_layout_item_field_is_same_field_exists(T_Container& container, const std::shared_ptr<const LayoutItem_Field>& layout_item)
{
return Utils::find_if_exists(container,
[&layout_item](const typename T_Container::value_type& element)
{
//Assume that element is a shared_ptr<>.
if(!layout_item && !element)
return true;
//Allow this to be used on a container of LayoutItems,
//as well as just of LayoutItem_Fields.
const auto element_field = std::dynamic_pointer_cast<const LayoutItem_Field>(element);
if(!element_field)
return false;
return layout_item && layout_item->is_same_field(element_field);
}
);
}
} //namespace Utils
} //namespace Glom
#endif //GLOM_LAYOUT_UTILS_H
......@@ -24,7 +24,6 @@
#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>
#include <libglom/string_utils.h>
......@@ -119,284 +118,6 @@ Glib::ustring Utils::locale_language_id(const Glib::ustring& locale_id)
}
}
Glib::ustring Utils::get_list_of_layout_items_for_display(const LayoutGroup::type_list_items& list_layout_fields)
{
Glib::ustring result;
for(const auto& item : list_layout_fields)
{
if(item)
{
if(!result.empty())
result += ", ";
result += item->get_layout_display_name();
}
}
return result;
}
Glib::ustring Utils::get_list_of_layout_items_for_display(const std::shared_ptr<const LayoutGroup>& layout_group)
{
if(layout_group)
return get_list_of_layout_items_for_display(layout_group->m_list_items);
else
return Glib::ustring();
}
Glib::ustring Utils::get_list_of_sort_fields_for_display(const Formatting::type_list_sort_fields& sort_fields)
{
Glib::ustring text;
for(const auto& the_pair : sort_fields)
{
const auto item = the_pair.first;
if(!item)
continue;
if(!text.empty())
text += ", ";
text += item->get_layout_display_name();
//TODO: Show Ascending/Descending?
}
return text;
}
LayoutGroup::type_list_const_items Utils::get_layout_items_plus_primary_key(const LayoutGroup::type_list_const_items& items, const std::shared_ptr<const Document>& document, const Glib::ustring& table_name)
{
if(!document)
{
std::cerr << G_STRFUNC << ": document was null.\n";
return items;
}
const auto field_primary_key = document->get_field_primary_key(table_name);
if(!field_primary_key)
{
std::cerr << G_STRFUNC << ": Could not find the primary key.\n";
return items;
}
auto pk_layout_item = std::make_shared<LayoutItem_Field>();
pk_layout_item->set_hidden();
pk_layout_item->set_full_field_details(field_primary_key);
if(find_if_layout_item_field_is_same_field_exists(items, pk_layout_item))
return items; //It is already in the list:
LayoutGroup::type_list_const_items items_plus_pk = items;
items_plus_pk.emplace_back(pk_layout_item);
return items_plus_pk;
}
//TODO: Avoid the horrible code duplication with the const version.
LayoutGroup::type_list_items Utils::get_layout_items_plus_primary_key(const LayoutGroup::type_list_items& items, const std::shared_ptr<const Document>& document, const Glib::ustring& table_name)
{
if(!document)
{
std::cerr << G_STRFUNC << ": document was null.\n";
return items;
}
const auto field_primary_key = document->get_field_primary_key(table_name);
if(!field_primary_key)
{
std::cerr << G_STRFUNC << ": Could not find the primary key.\n";
return items;
}
auto pk_layout_item = std::make_shared<LayoutItem_Field>();
pk_layout_item->set_hidden();
pk_layout_item->set_full_field_details(field_primary_key);
if(find_if_layout_item_field_is_same_field_exists(items, pk_layout_item))
return items; //It is already in the list:
LayoutGroup::type_list_items items_plus_pk = items;
items_plus_pk.emplace_back(pk_layout_item);
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));