[C++options] Implement new GncOptionValue type GncOptionReportPlacement.

For multicolumn reports so that we don't have to pass Scheme values.
This commit is contained in:
John Ralls 2022-03-21 12:46:02 -07:00
parent 5457d4a9e3
commit 278aa484d7
13 changed files with 303 additions and 257 deletions

View File

@ -24,6 +24,7 @@
#include <libguile.h>
#include <glib/gi18n.h>
#include <gtk/gtk.h>
#include <algorithm>
extern "C"
{
@ -41,7 +42,7 @@ extern "C"
#include "dialog-report-column-view.hpp"
#include <dialog-options.hpp>
#include <gnc-report.h>
#include <gnc-optiondb.h>
#include <gnc-optiondb-impl.hpp>
enum available_cols
{
@ -59,6 +60,8 @@ enum contents_cols
NUM_CONTENTS_COLS
};
using StrVec = std::vector<std::string>;
struct gncp_column_view_edit
{
GncOptionsDialog * optwin;
@ -68,8 +71,8 @@ struct gncp_column_view_edit
SCM view;
GncOptionDB * odb;
SCM available_list;
SCM contents_list;
StrVec available_list;
GncOptionReportPlacementVec contents_list;
int contents_selected;
GtkWidget *add_button;
@ -95,9 +98,9 @@ void gnc_column_view_edit_size_cb(GtkButton * button, gpointer user_data);
static void
gnc_column_view_set_option(GncOptionDB* odb, const char* section,
const char* name, SCM new_value)
const char* name, const GncOptionReportPlacementVec& new_value)
{
gnc_option_db_set_scm_value(odb, section, name, new_value);
odb->find_option(section, name)->set_value(new_value);
}
static void
@ -109,25 +112,28 @@ gnc_column_view_edit_destroy(gnc_column_view_edit * view)
g_free(view);
}
static StrVec
get_available_reports ()
{
StrVec sv;
auto scm_list{scm_call_0(scm_c_eval_string("gnc:all-report-template-guids"))};
for (auto next{scm_list}; !scm_is_null(next); next = scm_cdr(next))
sv.emplace_back(scm_to_utf8_string(scm_car(next)));
return sv;
}
static void
update_available_lists(gnc_column_view_edit * view)
{
SCM get_rpt_guids = scm_c_eval_string("gnc:all-report-template-guids");
SCM template_menu_name = scm_c_eval_string("gnc:report-template-menu-name/report-guid");
SCM rpt_guids = scm_call_0(get_rpt_guids);
SCM selection;
std::string selection;
gchar *name;
gchar *guid_str;
GtkTreeModel *model;
GtkListStore *store;
GtkTreeIter iter;
GtkTreeSelection *tree_selection;
/* Update the list of available reports (left selection box). */
tree_selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(view->available));
model = gtk_tree_view_get_model (GTK_TREE_VIEW(view->available));
auto tree_selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(view->available));
auto model = gtk_tree_view_get_model (GTK_TREE_VIEW(view->available));
if (gtk_tree_selection_get_selected(tree_selection, &model, &iter))
{
@ -135,41 +141,30 @@ update_available_lists(gnc_column_view_edit * view)
gtk_tree_model_get(model, &iter,
AVAILABLE_COL_GUID, &guid_str,
-1);
selection = scm_from_utf8_string(guid_str);
selection = std::string(guid_str);
g_free (guid_str);
}
else
selection = SCM_UNDEFINED;
view->available_list = get_available_reports();
scm_gc_unprotect_object(view->available_list);
view->available_list = rpt_guids;
scm_gc_protect_object(view->available_list);
store = GTK_LIST_STORE(model);
auto store = GTK_LIST_STORE(model);
gtk_list_store_clear(store);
if (scm_is_list(rpt_guids))
for (auto guid : view->available_list)
{
for (int i = 0; !scm_is_null(rpt_guids); rpt_guids = SCM_CDR(rpt_guids), i++)
{
SCM rpt_guids_temp = SCM_CAR(rpt_guids);
auto rpt_guid{scm_from_utf8_string(guid.c_str())};
auto name =
gnc_scm_to_utf8_string (scm_call_2(template_menu_name, rpt_guid, SCM_BOOL_F));
guid_str = scm_to_utf8_string (rpt_guids_temp);
name = gnc_scm_to_utf8_string (scm_call_2(template_menu_name, rpt_guids_temp,
SCM_BOOL_F));
gtk_list_store_append(store, &iter);
gtk_list_store_set(store, &iter,
AVAILABLE_COL_NAME, _(name),
AVAILABLE_COL_GUID, guid.c_str(),
-1);
gtk_list_store_append(store, &iter);
gtk_list_store_set(store, &iter,
AVAILABLE_COL_NAME, _(name),
AVAILABLE_COL_GUID, guid_str,
-1);
if (guid == selection)
gtk_tree_selection_select_iter (tree_selection, &iter);
if (scm_is_equal (rpt_guids_temp, selection))
gtk_tree_selection_select_iter (tree_selection, &iter);
g_free (name);
g_free (guid_str);
}
g_free (name);
}
}
@ -177,43 +172,25 @@ static void
update_contents_lists(gnc_column_view_edit * view)
{
SCM report_menu_name = scm_c_eval_string("gnc:report-menu-name");
SCM contents = gnc_option_db_lookup_scm_value(view->odb, "__general",
"report-list");
SCM this_report;
SCM selection = SCM_UNDEFINED;
GtkListStore *store;
auto contents{view->odb->find_option("__general", "report-list")->get_value<GncOptionReportPlacementVec>()};
GtkTreeIter iter;
GtkTreeSelection *tree_selection;
GncOptionReportPlacement selection{0, 0, 0};
/* Update the list of selected reports (right selection box). */
tree_selection = gtk_tree_view_get_selection(view->contents);
auto tree_selection = gtk_tree_view_get_selection(view->contents);
if (scm_is_list(view->contents_list) && !scm_is_null (view->contents_list))
{
int row = view->contents_selected;
row = MIN (row, scm_ilength (view->contents_list) - 1);
selection = scm_list_ref (view->contents_list, scm_from_int (row));
}
scm_gc_unprotect_object(view->contents_list);
view->contents_list = contents;
scm_gc_protect_object(view->contents_list);
store = GTK_LIST_STORE(gtk_tree_view_get_model(view->contents));
if (!contents.empty() && static_cast<size_t>(view->contents_selected) < contents.size())
selection = contents[view->contents_selected];
auto store = GTK_LIST_STORE(gtk_tree_view_get_model(view->contents));
gtk_list_store_clear(store);
if (!scm_is_list(contents))
return;
for (int i = 0; !scm_is_null(contents);
contents = SCM_CDR(contents), ++i)
for (size_t i = 0; i < contents.size(); ++i)
{
SCM contents_temp = SCM_CAR(contents);
int id = scm_to_int(SCM_CAAR(contents));
this_report = gnc_report_find(id);
auto [id, wide, high] = contents[i];
auto this_report = gnc_report_find(id);
auto name = gnc_scm_to_utf8_string (scm_call_1(report_menu_name, this_report));
gtk_list_store_append(store, &iter);
@ -221,11 +198,11 @@ update_contents_lists(gnc_column_view_edit * view)
(store, &iter,
CONTENTS_COL_NAME, _(name),
CONTENTS_COL_ROW, i,
CONTENTS_COL_REPORT_COLS, scm_to_int(SCM_CADR(contents_temp)),
CONTENTS_COL_REPORT_ROWS, scm_to_int(SCM_CADDR(contents_temp)),
CONTENTS_COL_REPORT_COLS, wide,
CONTENTS_COL_REPORT_ROWS, high,
-1);
if (scm_is_equal (contents_temp, selection))
if (id == std::get<0>(selection))
gtk_tree_selection_select_iter (tree_selection, &iter);
g_free (name);
@ -256,7 +233,7 @@ gnc_column_view_update_buttons_cb (GtkTreeSelection *selection,
if (is_selected)
{
int len = scm_ilength (reinterpret_cast<SCM>(r->contents_list));
int len = r->contents_list.size();
gtk_tree_model_get (model, &iter,
CONTENTS_COL_ROW, &r->contents_selected, -1);
@ -366,9 +343,9 @@ gnc_column_view_edit_options(GncOptionDB* odb, SCM view)
r->size_button = GTK_WIDGET(gtk_builder_get_object (builder, "size_button1"));
r->view = view;
r->available_list = SCM_EOL;
r->available_list.clear();
r->contents_selected = 0;
r->contents_list = SCM_EOL;
r->contents_list.clear();
r->odb = odb;
r->optwin->build_contents(r->odb);
@ -378,8 +355,6 @@ gnc_column_view_edit_options(GncOptionDB* odb, SCM view)
gtk_label_new(_("Contents")));
scm_gc_protect_object(r->view);
scm_gc_protect_object(r->available_list);
scm_gc_protect_object(r->contents_list);
/* Build the 'available' view */
store = gtk_list_store_new (NUM_AVAILABLE_COLS, G_TYPE_STRING, G_TYPE_STRING);
@ -449,12 +424,6 @@ gnc_column_view_edit_add_cb(GtkButton * button, gpointer user_data)
auto r = static_cast<gnc_column_view_edit *>(user_data);
SCM make_report = scm_c_eval_string("gnc:make-report");
SCM mark_report = scm_c_eval_string("gnc:report-set-needs-save?!");
SCM template_name;
SCM new_report;
SCM newlist = SCM_EOL;
SCM oldlist = r->contents_list;
int count;
int oldlength, id;
gchar *guid_str;
GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(r->available));
GtkTreeModel *model;
@ -467,55 +436,26 @@ gnc_column_view_edit_add_cb(GtkButton * button, gpointer user_data)
else
return;
if (scm_is_list(r->available_list))
auto template_name = scm_from_utf8_string(guid_str);
auto new_report = scm_call_1(make_report, template_name);
auto id = scm_to_int(new_report);
scm_call_2(mark_report, gnc_report_find(id), SCM_BOOL_T);
auto oldlength = r->contents_list.size();
GncOptionReportPlacement new_rpt_placement{id, 1, 1};
if (oldlength > static_cast<size_t>(r->contents_selected))
r->contents_list.emplace(r->contents_list.begin() + r->contents_selected + 1, id, 1, 1);
else
{
template_name = scm_from_utf8_string(guid_str);
new_report = scm_call_1(make_report, template_name);
id = scm_to_int(new_report);
scm_call_2(mark_report, gnc_report_find(id), SCM_BOOL_T);
oldlength = scm_ilength(r->contents_list);
if (oldlength > r->contents_selected)
{
for (count = 0; count < r->contents_selected; count++)
{
newlist = scm_cons(SCM_CAR(oldlist), newlist);
oldlist = SCM_CDR(oldlist);
}
newlist = scm_append
(scm_list_n (scm_reverse
(scm_cons
(scm_list_4 (new_report,
scm_from_int (1),
scm_from_int (1),
SCM_BOOL_F),
newlist)),
oldlist,
SCM_UNDEFINED));
}
else
{
newlist = scm_append
(scm_list_n (oldlist,
scm_list_1
(scm_list_4 (new_report,
scm_from_int (1),
scm_from_int (1),
SCM_BOOL_F)),
SCM_UNDEFINED));
r->contents_selected = oldlength;
}
scm_gc_unprotect_object(r->contents_list);
r->contents_list = newlist;
scm_gc_protect_object(r->contents_list);
gnc_column_view_set_option(r->odb, "__general", "report-list",
r->contents_list);
r->optwin->changed ();
r->contents_list.emplace_back(id, 1, 1);
r->contents_selected = oldlength;
}
gnc_column_view_set_option(r->odb, "__general", "report-list",
r->contents_list);
g_free (guid_str);
r->optwin->changed();
update_contents_lists(r);
}
@ -523,41 +463,34 @@ void
gnc_column_view_edit_remove_cb(GtkButton * button, gpointer user_data)
{
auto r = static_cast<gnc_column_view_edit *>(user_data);
SCM newlist = SCM_EOL;
SCM oldlist = r->contents_list;
int count;
int oldlength;
if (scm_is_list(r->contents_list))
{
oldlength = scm_ilength(r->contents_list);
if (oldlength > r->contents_selected)
{
for (count = 0; count < r->contents_selected; count++)
{
newlist = scm_cons(SCM_CAR(oldlist), newlist);
oldlist = SCM_CDR(oldlist);
}
if (count <= oldlength)
{
newlist = scm_append(scm_list_n (scm_reverse(newlist), SCM_CDR(oldlist), SCM_UNDEFINED));
}
}
r->contents_list.erase(r->contents_list.begin() + r->contents_selected);
if (r->contents_selected)
--r->contents_selected;
gnc_column_view_set_option(r->odb, "__general", "report-list",
r->contents_list);
if (r->contents_selected > 0 && oldlength == r->contents_selected + 1)
{
r->contents_selected --;
}
r->optwin->changed();
update_contents_lists(r);
}
scm_gc_unprotect_object(r->contents_list);
r->contents_list = newlist;
scm_gc_protect_object(r->contents_list);
static void
move_selected_item(gnc_column_view_edit* r, int increment)
{
if (!r || !increment)
return;
gnc_column_view_set_option(r->odb, "__general", "report-list",
r->contents_list);
auto cur_sel{r->contents_list.begin() + r->contents_selected};
auto move_to{cur_sel + increment};
if (increment > 0)
std::reverse(cur_sel, move_to + 1);
else
std::reverse(move_to, cur_sel + 1);
r->contents_selected += increment;
r->optwin->changed();
}
gnc_column_view_set_option(r->odb, "__general", "report-list",
r->contents_list);
r->optwin->changed();
update_contents_lists(r);
}
@ -565,76 +498,14 @@ void
gnc_edit_column_view_move_up_cb(GtkButton * button, gpointer user_data)
{
auto r = static_cast<gnc_column_view_edit *>(user_data);
SCM oldlist = r->contents_list;
SCM newlist = SCM_EOL;
SCM temp;
int oldlength;
int count;
oldlength = scm_ilength(r->contents_list);
if ((r->contents_selected > 0) && (oldlength > r->contents_selected))
{
for (count = 1; count < r->contents_selected; count++)
{
newlist = scm_cons(SCM_CAR(oldlist), newlist);
oldlist = SCM_CDR(oldlist);
}
temp = SCM_CAR(oldlist);
oldlist = SCM_CDR(oldlist);
newlist = scm_cons(temp, scm_cons(SCM_CAR(oldlist), newlist));
newlist = scm_append(scm_list_n (scm_reverse(newlist), SCM_CDR(oldlist), SCM_UNDEFINED));
scm_gc_unprotect_object(r->contents_list);
r->contents_list = newlist;
scm_gc_protect_object(r->contents_list);
r->contents_selected = r->contents_selected - 1;
gnc_column_view_set_option(r->odb, "__general", "report-list",
r->contents_list);
r->optwin->changed();
update_contents_lists(r);
}
move_selected_item(r, -1);
}
void
gnc_edit_column_view_move_down_cb(GtkButton * button, gpointer user_data)
{
auto r = static_cast<gnc_column_view_edit *>(user_data);
SCM oldlist = r->contents_list;
SCM newlist = SCM_EOL;
SCM temp;
int oldlength;
int count;
oldlength = scm_ilength(r->contents_list);
if (oldlength > (r->contents_selected + 1))
{
for (count = 0; count < r->contents_selected; count++)
{
newlist = scm_cons(SCM_CAR(oldlist), newlist);
oldlist = SCM_CDR(oldlist);
}
temp = SCM_CAR(oldlist);
oldlist = SCM_CDR(oldlist);
newlist = scm_cons(temp, scm_cons(SCM_CAR(oldlist), newlist));
newlist = scm_append(scm_list_n (scm_reverse(newlist), SCM_CDR(oldlist), SCM_UNDEFINED));
scm_gc_unprotect_object(r->contents_list);
r->contents_list = newlist;
scm_gc_protect_object(r->contents_list);
r->contents_selected = r->contents_selected + 1;
gnc_column_view_set_option(r->odb, "__general", "report-list",
r->contents_list);
r->optwin->changed();
update_contents_lists(r);
}
move_selected_item(r, 1);
}
void
@ -662,32 +533,27 @@ gnc_column_view_edit_size_cb(GtkButton * button, gpointer user_data)
rowspin = GTK_WIDGET(gtk_builder_get_object (builder, "row_spin"));
colspin = GTK_WIDGET(gtk_builder_get_object (builder, "col_spin"));
length = scm_ilength(r->contents_list);
if (length > r->contents_selected)
if (r->contents_list.size() > static_cast<size_t>(r->contents_selected))
{
current = scm_list_ref(r->contents_list,
scm_from_int (r->contents_selected));
auto [id, wide, high] = r->contents_list[r->contents_selected];
gtk_spin_button_set_value(GTK_SPIN_BUTTON(colspin),
(float)scm_to_int(SCM_CADR(current)));
static_cast<float>(wide));
gtk_spin_button_set_value(GTK_SPIN_BUTTON(rowspin),
(float)scm_to_int(SCM_CADDR(current)));
static_cast<float>(high));
dlg_ret = gtk_dialog_run(GTK_DIALOG(dlg));
gtk_widget_hide(dlg);
if (dlg_ret == GTK_RESPONSE_OK)
{
current = scm_list_4 (SCM_CAR (current),
scm_from_int (gtk_spin_button_get_value_as_int
(GTK_SPIN_BUTTON(colspin))),
scm_from_int (gtk_spin_button_get_value_as_int
(GTK_SPIN_BUTTON(rowspin))),
SCM_BOOL_F);
scm_gc_unprotect_object(r->contents_list);
r->contents_list = scm_list_set_x(r->contents_list,
scm_from_int (r->contents_selected),
current);
scm_gc_protect_object(r->contents_list);
std::get<1>(r->contents_list[r->contents_selected]) =
gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(colspin));
std::get<2>(r->contents_list[r->contents_selected]) =
gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(rowspin));
gnc_column_view_set_option(r->odb, "__general", "report-list",
r->contents_list);
r->optwin->changed();
update_contents_lists(r);
}

View File

@ -42,8 +42,7 @@
(gnc:register-option options opt))))
;; the report-list is edited by a special add-on page for the
;; options editor.
(opt-register
(gnc:make-internal-option "__general" "report-list" '()))
(gnc-register-report-placement-option (gnc:options-get options) "__general" "report-list")
(opt-register
(gnc:make-number-range-option
@ -83,7 +82,6 @@
(let* ((subreport (gnc-report-find (car report-info)))
(colspan (cadr report-info))
(rowspan (caddr report-info))
(opt-callback (cadddr report-info))
(toplevel-cell (gnc:make-html-table-cell/size rowspan colspan))
(report-table (gnc:make-html-table))
(contents-cell (gnc:make-html-table-cell)))

View File

@ -27,6 +27,8 @@
#include <guid.hpp>
#include <cassert>
#include <sstream>
#include <numeric>
extern "C"
{
#include "gnc-accounting-period.h"
@ -661,6 +663,18 @@ GncOptionValue<ValueType>::serialize() const noexcept
ostr << type << " " << guid;
return ostr.str();
}
if constexpr(std::is_same_v<ValueType, GncOptionReportPlacementVec>)
{
std::ostringstream ostr{};
ostr << "'(";
std::for_each(m_value.begin(), m_value.end(),
[&ostr](auto rp){
auto [id, wide, high] = rp;
ostr << "(" << id << " " << wide << " " << high << " #f) ";
});
ostr << ")";
return ostr.str();
}
else if constexpr(is_same_decayed_v<ValueType, std::string>)
return m_value;
else if constexpr(is_same_decayed_v<ValueType, bool>)
@ -684,6 +698,18 @@ GncOptionValue<ValueType>::deserialize(const std::string& str) noexcept
auto inst{qof_instance_from_string(guid, get_ui_type())};
qofOwnerSetEntity(const_cast<GncOwner*>(m_value), inst);
}
if constexpr(std::is_same_v<ValueType, GncOptionReportPlacementVec>)
{
std::istringstream istr{str};
GncOptionReportPlacementVec rpv;
while (istr)
{
uint32_t id, wide, high;
istr >> id >> wide >> high;
rpv.emplace_back(id, wide, high);
}
set_value(rpv);
}
else if constexpr(is_same_decayed_v<ValueType, std::string>)
set_value(str);
else if constexpr(is_same_decayed_v<ValueType, bool>)
@ -920,6 +946,7 @@ template GncOptionValue<RelativeDatePeriod>::GncOptionValue(const GncOptionValue
template GncOptionValue<size_t>::GncOptionValue(const GncOptionValue<size_t>&);
template GncOptionValue<GncOptionAccountList>::GncOptionValue(const GncOptionValue<GncOptionAccountList>&);
template GncOptionValue<GncMultichoiceOptionIndexVec>::GncOptionValue(const GncOptionValue<GncMultichoiceOptionIndexVec>&);
template GncOptionValue<GncOptionReportPlacementVec>::GncOptionValue(const GncOptionValue<GncOptionReportPlacementVec>&);
template GncOptionValue<SCM>::GncOptionValue(const GncOptionValue<SCM>&);
template void GncOptionValue<bool>::set_value(bool);
template void GncOptionValue<int>::set_value(int);
@ -934,6 +961,7 @@ template void GncOptionValue<RelativeDatePeriod>::set_value(RelativeDatePeriod);
template void GncOptionValue<size_t>::set_value(size_t);
template void GncOptionValue<GncOptionAccountList>::set_value(GncOptionAccountList);
template void GncOptionValue<GncMultichoiceOptionIndexVec>::set_value(GncMultichoiceOptionIndexVec);
template void GncOptionValue<GncOptionReportPlacementVec>::set_value(GncOptionReportPlacementVec);
template void GncOptionValue<bool>::set_default_value(bool);
template void GncOptionValue<int>::set_default_value(int);
template void GncOptionValue<int64_t>::set_default_value(int64_t);
@ -947,6 +975,7 @@ template void GncOptionValue<RelativeDatePeriod>::set_default_value(RelativeDate
template void GncOptionValue<size_t>::set_default_value(size_t);
template void GncOptionValue<GncOptionAccountList>::set_default_value(GncOptionAccountList);
template void GncOptionValue<GncMultichoiceOptionIndexVec>::set_default_value(GncMultichoiceOptionIndexVec);
template void GncOptionValue<GncOptionReportPlacementVec>::set_default_value(GncOptionReportPlacementVec);
template void GncOptionValue<bool>::reset_default_value();
template void GncOptionValue<int>::reset_default_value();
template void GncOptionValue<int64_t>::reset_default_value();
@ -960,6 +989,7 @@ template void GncOptionValue<RelativeDatePeriod>::reset_default_value();
template void GncOptionValue<size_t>::reset_default_value();
template void GncOptionValue<GncOptionAccountList>::reset_default_value();
template void GncOptionValue<GncMultichoiceOptionIndexVec>::reset_default_value();
template void GncOptionValue<GncOptionReportPlacementVec>::reset_default_value();
template std::string GncOptionValue<bool>::serialize() const noexcept;
template std::string GncOptionValue<int>::serialize() const noexcept;
template std::string GncOptionValue<int64_t>::serialize() const noexcept;
@ -970,6 +1000,7 @@ template std::string GncOptionValue<std::string>::serialize() const noexcept;
template std::string GncOptionValue<const QofQuery*>::serialize() const noexcept;
template std::string GncOptionValue<const GncOwner*>::serialize() const noexcept;
template std::string GncOptionValue<SCM>::serialize() const noexcept;
template std::string GncOptionValue<GncOptionReportPlacementVec>::serialize() const noexcept;
template std::string GncOptionRangeValue<int>::serialize() const noexcept;
template std::string GncOptionRangeValue<double>::serialize() const noexcept;
template bool GncOptionValue<bool>::deserialize(const std::string&) noexcept;
@ -982,5 +1013,6 @@ template bool GncOptionValue<std::string>::deserialize(const std::string&) noexc
template bool GncOptionValue<const QofQuery*>::deserialize(const std::string&) noexcept;
template bool GncOptionValue<const GncOwner*>::deserialize(const std::string&) noexcept;
template bool GncOptionValue<SCM>::deserialize(const std::string&) noexcept;
template bool GncOptionValue<GncOptionReportPlacementVec>::deserialize(const std::string&) noexcept;
template bool GncOptionRangeValue<int>::deserialize(const std::string&) noexcept;
template bool GncOptionRangeValue<double>::deserialize(const std::string&) noexcept;

View File

@ -331,6 +331,16 @@ operator>> <GncOptionValue<bool>>(std::istream& iss,
opt.set_value(instr == "#t" ? true : false);
return iss;
}
template<> inline std::istream&
operator>> <GncOptionValue<GncOptionReportPlacementVec>>(std::istream& iss,
GncOptionValue<GncOptionReportPlacementVec>& opt)
{
uint32_t id, wide, high;
iss >> id >> wide >> high;
opt.set_value(GncOptionReportPlacementVec{{id, wide, high}});
return iss;
}
#endif // SWIG
/** @class GncOptionRangeValue

View File

@ -67,7 +67,7 @@ enum class GncOptionUIType : unsigned int
JOB,
TAX_TABLE,
QUERY,
REPORT_LIST,
REPORT_PLACEMENT,
MAX_VALUE, //Nake sure this one is always last
};

View File

@ -481,6 +481,7 @@ template RelativeDatePeriod GncOption::get_value<RelativeDatePeriod>() const;
template GncOptionAccountList GncOption::get_value<GncOptionAccountList>() const;
template GncMultichoiceOptionIndexVec GncOption::get_value<GncMultichoiceOptionIndexVec>() const;
template SCM GncOption::get_value<SCM>() const;
template GncOptionReportPlacementVec GncOption::get_value<GncOptionReportPlacementVec>() const;
template bool GncOption::get_default_value<bool>() const;
template int GncOption::get_default_value<int>() const;
@ -495,6 +496,7 @@ template RelativeDatePeriod GncOption::get_default_value<RelativeDatePeriod>() c
template GncOptionAccountList GncOption::get_default_value<GncOptionAccountList>() const;
template GncMultichoiceOptionIndexVec GncOption::get_default_value<GncMultichoiceOptionIndexVec>() const;
template SCM GncOption::get_default_value<SCM>() const;
template GncOptionReportPlacementVec GncOption::get_default_value<GncOptionReportPlacementVec>() const;
template void GncOption::set_value(bool);
template void GncOption::set_value(int);
@ -511,6 +513,7 @@ template void GncOption::set_value(size_t);
template void GncOption::set_value(GncOptionAccountList);
template void GncOption::set_value(GncMultichoiceOptionIndexVec);
template void GncOption::set_value(SCM);
template void GncOption::set_value(GncOptionReportPlacementVec);
template void GncOption::set_default_value(bool);
template void GncOption::set_default_value(int);
@ -526,6 +529,7 @@ template void GncOption::set_default_value(size_t);
template void GncOption::set_default_value(GncOptionAccountList);
template void GncOption::set_default_value(GncMultichoiceOptionIndexVec);
template void GncOption::set_default_value(SCM);
template void GncOption::set_default_value(GncOptionReportPlacementVec);
template void GncOption::get_limits(double&, double&, double&) const noexcept;
template void GncOption::get_limits(int&, int&, int&) const noexcept;
@ -541,6 +545,7 @@ template bool GncOption::validate(const Account*) const;
template bool GncOption::validate(const QofQuery*) const;
template bool GncOption::validate(RelativeDatePeriod) const;
template bool GncOption::validate(GncMultichoiceOptionIndexVec) const;
template bool GncOption::validate(GncOptionReportPlacementVec) const;
template GncOption* gnc_make_option<const std::string&>(const char*,
const char*,
@ -554,3 +559,4 @@ template GncOption* gnc_make_option<int64_t>(const char*, const char*,
const char*, const char*, int64_t,
GncOptionUIType);

View File

@ -40,8 +40,10 @@
#include <iomanip>
#include <variant>
#include <memory>
#include <tuple>
#include "gnc-option-ui.hpp"
#include "gnc-option-date.hpp"
#include <guid.hpp>
struct OptionClassifier;
class GncOptionUIItem;
@ -62,7 +64,8 @@ class GncOptionMultichoiceValue;
template <typename ValueType> class GncOptionRangeValue;
class GncOptionCommodityValue;
class GncOptionDateValue;
using GncOptionReportPlacement = std::tuple<uint32_t, uint32_t, uint32_t>;
using GncOptionReportPlacementVec = std::vector<GncOptionReportPlacement>;
template <typename T>
struct is_OptionClassifier
{
@ -102,6 +105,7 @@ using GncOptionVariant = std::variant<GncOptionValue<std::string>,
GncOptionValue<const QofQuery*>,
GncOptionValue<const GncOwner*>,
GncOptionValue<SCM>,
GncOptionValue<GncOptionReportPlacementVec>,
GncOptionAccountListValue,
GncOptionAccountSelValue,
GncOptionMultichoiceValue,

View File

@ -840,6 +840,7 @@ gnc_register_internal_option(GncOptionDB* db, const char* section,
GncOptionUIType::INTERNAL};
db->register_option(section, std::move(option));
}
void
gnc_register_invoice_option(GncOptionDB* db, const char* section,
const char* name, const char* key,
@ -995,6 +996,20 @@ gnc_register_end_date_option(GncOptionDB* db, const char* section,
db->register_option(section, std::move(option));
}
void
gnc_register_report_placement_option(GncOptionDBPtr& db,
const char* section, const char* name)
{
/* This is a special option with it's own UI file so we have fake values to pass
* to the template creation function.
*/
GncOptionReportPlacementVec value;
GncOption option{GncOptionValue<GncOptionReportPlacementVec>{section, name,
"no_key", "nodoc_string",
value,GncOptionUIType::REPORT_PLACEMENT}};
db->register_option(section, std::move(option));
}
GncOptionDB*
gnc_option_db_new(void)
{

View File

@ -600,6 +600,21 @@ inline void gnc_register_internal_option(GncOptionDBPtr& db,
doc_string, value);
}
void gnc_register_internal_option(GncOptionDBPtr& db,
const char* section, const char* name,
const char* key,
const char* doc_string,
const std::string& value);
void gnc_register_internal_option(GncOptionDBPtr& db,
const char* section, const char* name,
const char* key,
const char* doc_string,
bool value);
void gnc_register_report_placement_option(GncOptionDBPtr& db,
const char* section, const char* name);
/**
* Create a new currency option and register it in the options database.
*

View File

@ -274,6 +274,39 @@ scm_from_value<GncOwner*>(GncOwner* value)
return scm_from_value<const GncOwner*>(value);
}
template <>inline SCM
scm_from_value<GncOptionAccountList>(GncOptionAccountList value)
{
SCM s_list = SCM_EOL;
auto book{gnc_get_current_book()};
for (auto guid : value)
{
auto acct{xaccAccountLookup(&guid, book)};
s_list = scm_cons(SWIG_NewPointerObj(acct, SWIGTYPE_p_Account, 0),
s_list);
}
return scm_reverse(s_list);
}
template <>inline SCM
scm_from_value<GncOptionReportPlacementVec>(GncOptionReportPlacementVec value)
{
SCM s_list = SCM_EOL;
for (auto placement : value)
{
auto [id, wide, high] = placement;
auto scm_id{scm_from_uint32(id)};
auto scm_wide{scm_from_uint32(wide)};
auto scm_high{scm_from_uint32(high)};
/* The trailing SCM_BOOL_F is a placeholder for a never-used callback function,
* present for backward compatibility so that older GnuCash versions can load a
* saved multicolumn report.
*/
s_list = scm_cons(scm_list_4(scm_id, scm_wide, scm_high, SCM_BOOL_F), s_list);
}
return scm_reverse(s_list);
}
static std::string
scm_color_list_to_string(SCM list)
{
@ -440,18 +473,25 @@ scm_to_value<GncOptionAccountList>(SCM new_value)
return retval;
}
template <>inline SCM
scm_from_value<GncOptionAccountList>(GncOptionAccountList value)
template <>inline GncOptionReportPlacementVec
scm_to_value<GncOptionReportPlacementVec>(SCM new_value)
{
SCM s_list = SCM_EOL;
auto book{gnc_get_current_book()};
for (auto guid : value)
GncOptionReportPlacementVec rp;
GncOptionAccountList retval{};
if (scm_is_false(scm_list_p(new_value)) || scm_is_null(new_value))
return rp;
auto next{new_value};
while (auto node{scm_car(next)})
{
auto acct{xaccAccountLookup(&guid, book)};
s_list = scm_cons(SWIG_NewPointerObj(acct, SWIGTYPE_p_Account, 0),
s_list);
auto id{scm_to_uint32(scm_car(node))};
auto wide{scm_to_uint32(scm_cadr(node))};
auto high{scm_to_uint32(scm_caddr(node))};
rp.emplace_back(id, wide, high);
next = scm_cdr(next);
if (scm_is_null(next))
break;
}
return scm_reverse(s_list);
return rp;
}
QofBook* gnc_option_test_book_new();
@ -640,6 +680,12 @@ gnc_option_test_book_destroy(QofBook* book)
$1 = &acclist;
}
%typemap (in) GncOptionReportPlacementVec& (GncOptionReportPlacementVec rp)
{
rp = scm_to_value<GncOptionReportPlacementVec>($input);
$1 = &rp;
}
%typemap(out) GncOptionAccountList
{
$result = SCM_EOL;
@ -666,6 +712,11 @@ gnc_option_test_book_destroy(QofBook* book)
$result = scm_reverse ($result)
}
%typemap(out) const GncOptionReportPlacementVec&
{
$result = scm_from_value<GncOptionReportPlacementVec>($1);
}
wrap_unique_ptr(GncOptionDBPtr, GncOptionDB);
%ignore swig_get_option(GncOption&);
@ -709,7 +760,6 @@ wrap_unique_ptr(GncOptionDBPtr, GncOptionDB);
%ignore gnc_register_number_Plot_size_option(GncOptionDB*, const char*, const char*, const char*, const char*, int);
%ignore gnc_register_query_option(GncOptionDB*, const char*, const char*, const char*, const char*, QofQuery*);
%ignore gnc_register_color_option(GncOptionDB*, const char*, const char*, const char*, const char*, std::string);
%ignore gnc_register_internal_option(GncOptionDB*, const char*, const char*, const char*, const char*, std::string);
%ignore gnc_register_currency_option(GncOptionDB*, const char*, const char*, const char*, const char*, gnc_commodity*);
%ignore gnc_register_invoice_option(GncOptionDB*, const char*, const char*, const char*, const char*, GncInvoice*);
%ignore gnc_register_taxtable_option(GncOptionDB*, const char*, const char*, const char*, const char*, GncTaxTable*);
@ -721,7 +771,8 @@ wrap_unique_ptr(GncOptionDBPtr, GncOptionDB);
%ignore gnc_register_date_option(GncOptionDB*, const char*, const char*, const char*, const char*, RelativeDatePeriodVec, bool);
%ignore gnc_register_start_date_option(GncOptionDB*, const char*, const char*, const char*, const char*, bool);
%ignore gnc_register_end_date_option(GncOptionDB*, const char*, const char*, const char*, const char*, bool);
%ignore gnc_register_internal_option(GncOptionDBPtr&, const char*, const char*, const char*, const char*, const std::string&);
%ignore gnc_register_internal_option(GncOptionDBPtr&, const char*, const char*, const char*, const char*, bool);
%typemap(in) GncOption* "$1 = scm_is_true($input) ? static_cast<GncOption*>(scm_to_pointer($input)) : nullptr;"
%typemap(out) GncOption* "$result = ($1) ? scm_from_pointer($1, nullptr) : SCM_BOOL_F;"
@ -1057,7 +1108,6 @@ inline SCM return_scm_value(ValueType value)
%template(gnc_make_int64_option) gnc_make_option<int64_t>;
%template(gnc_make_query_option) gnc_make_option<const QofQuery*>;
%template(gnc_make_owner_option) gnc_make_option<const GncOwner*>;
%extend GncOption {
bool is_budget_option()
{
@ -1200,6 +1250,13 @@ inline SCM return_scm_value(ValueType value)
return scm_simple_format(SCM_BOOL_F, ticked_format_str,
scm_val);
}
if constexpr (is_same_decayed_v<decltype(option),
GncOptionValue<GncOptionReportPlacementVec>>)
{
auto scm_val{scm_list_1(return_scm_value(option.get_value()))};
return scm_simple_format(SCM_BOOL_F, ticked_format_str,
scm_val);
}
auto serial{option.serialize()};
if (serial.empty())
{

View File

@ -1311,3 +1311,19 @@ TEST_F(GncDateOption, test_stream_in_prev_year_end)
EXPECT_EQ(time1, m_option.get_value<time64>());
}
TEST(GncOption, test_create)
{
uint32_t report_id = 123;
uint32_t wide = 2, high = 2;
GncOptionReportPlacementVec rp{{report_id, wide, high}};
GncOptionValue<GncOptionReportPlacementVec> rpv("foo", "bar", "baz", "Phony Option", rp);
GncOption option{rpv};
auto value{option.get_value<GncOptionReportPlacementVec>()};
EXPECT_EQ(value.size(), 1);
auto [sid, swide, shigh] = value.at(0);
EXPECT_EQ(report_id, sid);
EXPECT_EQ(wide, swide);
EXPECT_EQ(high, shigh);
}

View File

@ -81,6 +81,21 @@ TEST_F(GncOptionDBTest, test_register_string_option)
EXPECT_STREQ("waldo", m_db->lookup_string_option("foo", "bar").c_str());
}
TEST_F(GncOptionDBTest, test_register_report_placement_option)
{
uint32_t report_id = 456;
uint32_t wide = 2, high = 2;
GncOptionReportPlacementVec rp{{report_id, wide, high}};
gnc_register_report_placement_option(m_db, "foo", "bar");
auto option{m_db->find_option("foo", "bar")};
option->set_value(rp);
auto value{option->get_value<GncOptionReportPlacementVec>()};
EXPECT_EQ(value.size(), 1);
auto [v_id, v_wide, v_height] = value.at(0);
EXPECT_EQ(report_id, v_id);
}
/* Note: The following test-fixture code is also present in slightly different
* form in gtest-gnc-option.cpp.
*/

View File

@ -54,6 +54,7 @@
(test-gnc-make-date-option)
(test-gnc-make-date-set-option)
(test-gnc-make-number-range-option)
(test-gnc-make-report-placement-option)
(test-end "test-gnc-optiondb-scheme"))
(define (test-gnc-make-text-option)
@ -235,3 +236,14 @@
(gnc-set-option option-db "foo" "bar" 20)
(test-equal 20.0 (gnc-option-value option-db "foo" "bar")))
(test-end "test-gnc-number-range-option"))
(define (test-gnc-make-report-placement-option)
(test-begin "test-gnc-report-placement-option")
(let* ((report1 123)
(report2 456)
(rp (list (list report1 2 3) (list report2 3 2)))
(option-db (new-gnc-optiondb)))
(gnc-register-report-placement-option option-db "foo" "bar")
(gnc-set-option option-db "foo" "bar" rp)
(test-equal report2 (car (cadr (gnc-option-value option-db "foo" "bar")))))
(test-end "test-gnc-report-placement-option"))