3
* Copyright (C) 2001-2004 Murray Cumming
5
* This program is free software; you can redistribute it and/or
6
* modify it under the terms of the GNU General Public License as
7
* published by the Free Software Foundation; either version 2 of the
8
* License, or (at your option) any later version.
10
* This program is distributed in the hope that it will be useful, but
11
* WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
* General Public License for more details.
15
* You should have received a copy of the GNU General Public
16
* License along with this program; if not, write to the
17
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18
* Boston, MA 02111-1307, USA.
21
#include "canvas_layout_item.h"
22
#include <glom/utility_widgets/canvas/canvas_rect_movable.h>
23
#include <glom/utility_widgets/canvas/canvas_text_movable.h>
24
#include <glom/utility_widgets/canvas/canvas_image_movable.h>
25
#include <glom/utility_widgets/canvas/canvas_line_movable.h>
26
#include <glom/utility_widgets/canvas/canvas_group_movable.h>
27
#include <glom/utility_widgets/canvas/canvas_table_movable.h>
28
#include <glom/libglom/data_structure/layout/layoutitem_button.h>
29
#include <glom/libglom/data_structure/layout/layoutitem_text.h>
30
#include <glom/libglom/data_structure/layout/layoutitem_image.h>
31
#include <glom/libglom/data_structure/layout/layoutitem_field.h>
32
#include <glom/libglom/data_structure/layout/layoutitem_line.h>
33
#include <glom/libglom/data_structure/layout/layoutitem_portal.h>
34
#include <glom/libglom/data_structure/layout/report_parts/layoutitem_fieldsummary.h>
35
#include <glom/libglom/data_structure/glomconversions.h>
36
#include <glibmm/i18n.h>
38
#include <algorithm> //For std::max().
43
CanvasLayoutItem::CanvasLayoutItem()
45
//Rescale images when the canvas item is resized:
46
signal_resized().connect( sigc::mem_fun(*this, &CanvasLayoutItem::on_resized) );
49
CanvasLayoutItem::CanvasLayoutItem(const sharedptr<LayoutItem>& layout_item)
51
set_layout_item(layout_item);
53
//Rescale images when the canvas item is resized:
54
signal_resized().connect( sigc::mem_fun(*this, &CanvasLayoutItem::on_resized) );
57
CanvasLayoutItem::~CanvasLayoutItem()
61
Glib::RefPtr<CanvasLayoutItem> CanvasLayoutItem::create()
63
return Glib::RefPtr<CanvasLayoutItem>(new CanvasLayoutItem());
66
Glib::RefPtr<CanvasLayoutItem> CanvasLayoutItem::create(const sharedptr<LayoutItem>& layout_item)
68
return Glib::RefPtr<CanvasLayoutItem>(new CanvasLayoutItem(layout_item));
71
sharedptr<LayoutItem> CanvasLayoutItem::get_layout_item()
76
void CanvasLayoutItem::check_and_apply_formatting(const Glib::RefPtr<CanvasTextMovable>& canvas_item, FieldFormatting& formatting)
81
Glib::ustring font = formatting.get_text_format_font();
86
//Set it in the input parameter,
87
//so that this is the default:
88
formatting.set_text_format_font(font);
91
canvas_item->set_font_points(font);
93
//TODO: Are these sensible properties? Maybe we need to use markup:
94
const Glib::ustring fg = formatting.get_text_format_color_foreground();
96
canvas_item->property_stroke_color() = fg;
98
const Glib::ustring bg = formatting.get_text_format_color_background();
100
canvas_item->property_fill_color() = bg;
103
void CanvasLayoutItem::on_resized()
105
Glib::RefPtr<CanvasImageMovable> canvas_image = Glib::RefPtr<CanvasImageMovable>::cast_dynamic(get_child());
107
canvas_image->scale_to_size();
110
void CanvasLayoutItem::set_layout_item(const sharedptr<LayoutItem>& layout_item)
113
m_layout_item = layout_item;
116
std::cerr << "CanvasLayoutItem::set_layout_item(): item was NULL." << std::endl;
118
Glib::RefPtr<CanvasItemMovable> child_item = create_canvas_item_for_layout_item(m_layout_item);
122
//child_item->property_pointer_events() =
123
// (Goocanvas::PointerEvents)(Goocanvas::EVENTS_VISIBLE_FILL & GOO_CANVAS_EVENTS_VISIBLE_STROKE);
125
//Set the position and dimensions of this group to match the child:
130
m_layout_item->get_print_layout_position(x, y, width, height);
133
set_width_height(width, height);
134
//std::cout << "CanvasLayoutItem::set_layout_item(): item x=" << x << std::endl;
136
set_child(child_item);
140
//This can only be done after setting the size:
141
Glib::RefPtr<CanvasImageMovable> canvas_image = Glib::RefPtr<CanvasImageMovable>::cast_dynamic(child_item);
144
canvas_image->scale_to_size();
148
int CanvasLayoutItem::get_rows_count_for_portal(const sharedptr<const LayoutItem_Portal>& portal, double& row_height)
156
row_height = std::max(portal->get_print_layout_row_height(), (double)1); //Avoid 0, because that makes the whole thing zero sized.
160
double total_width = 0;
161
double total_height = 0;
162
portal->get_print_layout_position(ignore_x, ignore_y, total_width, total_height);
164
const double max_rows_fraction = total_height / row_height;
166
modf(max_rows_fraction, &max_rows);
171
Glib::RefPtr<CanvasItemMovable> CanvasLayoutItem::create_canvas_item_for_layout_item(const sharedptr<LayoutItem>& layout_item)
173
sharedptr<LayoutItem_Line> line;
175
Glib::RefPtr<CanvasItemMovable> child;
176
Glib::RefPtr<Goocanvas::Item> child_item;
177
sharedptr<LayoutItem_Text> text = sharedptr<LayoutItem_Text>::cast_dynamic(layout_item);
180
Glib::RefPtr<CanvasTextMovable> canvas_item = CanvasTextMovable::create();
181
canvas_item->property_line_width() = 0;
183
FieldFormatting& formatting = text->m_formatting;
184
check_and_apply_formatting(canvas_item, formatting);
186
canvas_item->set_text(text->get_text());
188
child_item = canvas_item;
192
sharedptr<LayoutItem_Image> image = sharedptr<LayoutItem_Image>::cast_dynamic(layout_item);
195
Glib::RefPtr<CanvasImageMovable> canvas_item = CanvasImageMovable::create();
196
Glib::RefPtr<Gdk::Pixbuf> pixbuf = image->get_image_as_pixbuf();
198
canvas_item->set_image(pixbuf);
200
canvas_item->set_image_empty(); //show a no-image picture.
202
canvas_item->property_fill_color() = "white"; //This makes the whole area clickable, not just the outline stroke.
204
child_item = canvas_item;
208
sharedptr<LayoutItem_Line> line = sharedptr<LayoutItem_Line>::cast_dynamic(layout_item);
215
line->get_coordinates(start_x, start_y, end_x, end_y);
217
Glib::RefPtr<CanvasLineMovable> canvas_item = CanvasLineMovable::create();
218
canvas_item->property_line_width() = 1;
219
canvas_item->property_stroke_color() = "black";
221
Goocanvas::Points points(2);
222
points.set_coordinate(0, start_x, start_y);
223
points.set_coordinate(0, end_x, end_y);
224
canvas_item->property_points() = points;
226
child_item = canvas_item;
230
sharedptr<LayoutItem_Field> field = sharedptr<LayoutItem_Field>::cast_dynamic(layout_item);
233
//Create an appropriate canvas item for the field type:
234
if(field->get_glom_type() == Field::TYPE_IMAGE)
236
Glib::RefPtr<CanvasImageMovable> canvas_item = CanvasImageMovable::create();
237
canvas_item->set_image_empty();
240
child_item = canvas_item;
242
else //text, numbers, date, time, boolean:
244
Glib::RefPtr<CanvasTextMovable> canvas_item = CanvasTextMovable::create();
245
canvas_item->property_line_width() = 0;
247
FieldFormatting& formatting = field->m_formatting;
248
check_and_apply_formatting(canvas_item, formatting);
250
Glib::ustring name = field->get_name();
252
name = _("Choose Field");
254
canvas_item->set_text(name);
257
child_item = canvas_item;
262
sharedptr<LayoutItem_Portal> portal = sharedptr<LayoutItem_Portal>::cast_dynamic(layout_item);
265
Glib::RefPtr<CanvasTableMovable> canvas_item = CanvasTableMovable::create();
266
canvas_item->property_vert_grid_line_width() = 1;
267
canvas_item->property_horz_grid_line_width() = 1;
268
canvas_item->property_stroke_color() = "black";
270
//Show as many rows as can fit in the height.
271
double row_height = 0;
272
const int max_rows = get_rows_count_for_portal(portal, row_height);
274
const LayoutGroup::type_list_items child_items = portal->get_items();
276
for(guint row = 0; row < (guint)max_rows; ++row)
279
for(LayoutGroup::type_list_items::const_iterator iter = child_items.begin(); iter != child_items.end(); ++iter)
281
sharedptr<LayoutItem> layout_item = *iter;
283
//We use create_canvas_item_for_layout_item() instead of just
284
//creating another CanvasLayoutItem, because that would be a group,
285
//but goocanvas cannot yet support Groups inside Tables. murrayc.
287
Glib::RefPtr<CanvasItemMovable> cell = create_canvas_item_for_layout_item(layout_item);
290
//Make sure that the width is sensible:
292
layout_item->get_display_width(width);
293
width = std::max(width, (guint)10);
294
cell->set_width_height(width, row_height);
295
std::cout << "DEBUG: width=" << width << std::endl;
297
//TODO: Add/Remove rows when resizing, instead of resizing the rows:
298
Glib::RefPtr<Goocanvas::Item> cell_as_item = CanvasItemMovable::cast_to_item(cell);
301
canvas_item->attach(cell_as_item,
302
col /* left_attach */, col+1 /* right_attach */,
303
row /* top_attach */, row + 1 /* right_attach */,
304
Gtk::FILL, (Gtk::AttachOptions)Gtk::FILL | Gtk::EXPAND);
313
child_item = canvas_item;
317
std::cerr << "CanvasLayoutItem::set_layout_item(): Unhandled LayoutItem type. part type=" << layout_item->get_part_type_name() << std::endl;
321
std::cerr << "CanvasLayoutItem::set_layout_item(): NULL LayoutItem type." << std::endl;
330
if(child && child_item)
332
//child_item->property_pointer_events() =
333
// (Goocanvas::PointerEvents)(Goocanvas::EVENTS_VISIBLE_FILL & GOO_CANVAS_EVENTS_VISIBLE_STROKE);
335
//Set the position and dimensions of this group to match the child:
340
layout_item->get_print_layout_position(x, y, width, height);
341
child->set_width_height(width, height);
342
//std::cout << "CanvasLayoutItem::set_layout_item(): item x=" << x << std::endl;
346
//This can only be done after setting the size:
347
Glib::RefPtr<CanvasImageMovable> canvas_image = Glib::RefPtr<CanvasImageMovable>::cast_dynamic(child);
350
canvas_image->scale_to_size();
352
//It will also be rescaled when this canvas item is resized - see on_resized().
358
void CanvasLayoutItem::set_db_data(const Gnome::Gda::Value& value)
360
sharedptr<LayoutItem_Field> field = sharedptr<LayoutItem_Field>::cast_dynamic(m_layout_item);
364
Glib::RefPtr<CanvasItemMovable> child = get_child();
368
const Field::glom_field_type field_type = field->get_glom_type();
369
switch(field->get_glom_type())
371
case(Field::TYPE_TEXT):
372
case(Field::TYPE_NUMERIC):
373
case(Field::TYPE_BOOLEAN):
374
case(Field::TYPE_TIME):
375
case(Field::TYPE_DATE):
377
Glib::RefPtr<CanvasTextMovable> canvas_item = Glib::RefPtr<CanvasTextMovable>::cast_dynamic(child);
381
Glib::ustring text_value = Conversions::get_text_for_gda_value(field_type, value, field->get_formatting_used().m_numeric_format);
383
//The Postgres summary functions return NULL when summarising NULL records, but 0 is more sensible:
384
if(text_value.empty() && sharedptr<const LayoutItem_FieldSummary>::cast_dynamic(field) && (field_type == Field::TYPE_NUMERIC))
386
//Use get_text_for_gda_value() instead of "0" so we get the correct numerical formatting:
387
Gnome::Gda::Value value = Conversions::parse_value(0);
388
text_value = Conversions::get_text_for_gda_value(field_type, value, field->get_formatting_used().m_numeric_format);
391
canvas_item->set_text(text_value);
394
case(Field::TYPE_IMAGE):
396
Glib::RefPtr<CanvasImageMovable> canvas_item = Glib::RefPtr<CanvasImageMovable>::cast_dynamic(child);
400
//Get the height of the item (not of the pixbuf),
401
//so we can scale the pixbuf:
404
canvas_item->get_width_height(width, height);
406
Glib::RefPtr<Gdk::Pixbuf> pixbuf = Conversions::get_pixbuf_for_gda_value(value);
407
if(pixbuf) //TODO: Remove this if() check when goocanvas has my patch to avoid crashes when this is NULL.
408
canvas_item->set_image(pixbuf);
413
std::cerr << "CanvasLayoutItem::set_db_data(): unhandled field type." << std::endl;
418
void CanvasLayoutItem::remove_empty_indicators()
420
Glib::RefPtr<CanvasItemMovable> child = get_child();
421
Glib::RefPtr<CanvasImageMovable> canvas_image = Glib::RefPtr<CanvasImageMovable>::cast_dynamic(child);
424
//Clear the no-image pixbuf from images:
425
if(canvas_image->get_image_empty())
427
Glib::RefPtr<Gdk::Pixbuf> really_empty;
428
canvas_image->property_pixbuf() = really_empty;