1143
1159
if (w->drag_check_threshold(_drag_start_x, _drag_start_y, ev->x, ev->y))
1161
if (_org_event != 0)
1168
//Because of problems when Treeview has been set to multiselect,
1169
//there are some DnD problems, below code is fixing those.
1170
//We check if users already selected something,
1171
//if he is trying to drag not selected row,
1172
//we change selection.
1173
std::vector<Gtk::TreePath> path_selection;
1174
path_selection = _tree.get_selection()->get_selected_rows();
1176
Gtk::TreeModel::Path selpath;
1177
if(_tree.get_path_at_pos(_drag_start_x, _drag_start_y, selpath))
1180
for(std::vector<Gtk::TreePath>::iterator it = path_selection.begin(); it != path_selection.end(); ++it)
1190
//Old selection is invalid, we need to create new one
1191
_tree.get_selection()->unselect_all();
1192
_tree.get_selection()->select(selpath);
1145
1198
TreeNodeView *view = dynamic_cast<TreeNodeView*>(owner);
1148
1201
mforms::DragDetails details;
1151
if(view->get_drag_data(details, &data, format))
1153
std::vector<Gtk::TargetEntry> targets;
1154
targets.push_back(Gtk::TargetEntry(format,Gtk::TargetFlags(0),0));
1156
_tree.enable_model_drag_source(targets); // we need this to have D&D working
1157
_drag_in_progress = true;
1158
details.location = base::Point(ev->x, ev->y);
1159
details.allowedOperations = mforms::DragOperationCopy;
1162
Gtk::TreeModel::Path path;
1163
if(_tree.get_path_at_pos(_drag_start_x, _drag_start_y, path))
1165
//let's make better drag image,
1166
Glib::RefPtr<Gdk::Pixmap> row_icon = _tree.create_row_drag_icon(path);
1169
row_icon->get_size(ico_w, ico_h);
1170
Glib::RefPtr<Gdk::Pixbuf> pix = Gdk::Pixbuf::create(row_icon->get_image(0, 0, ico_w, ico_h), 0, 0, ico_w, ico_h);
1171
//sadly we need a cairo_surface
1172
details.image = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, ico_w, ico_h);
1173
cairo_t *cr = cairo_create(details.image);
1174
gdk_cairo_set_source_pixbuf(cr, pix->gobj(), 0, 0);
1177
mforms::DragOperation operation = view->do_drag_drop(details, data, format);
1178
cairo_surface_destroy(details.image);
1180
view->drag_finished(operation);
1186
details.location = base::Point(ev->x, ev->y);
1187
details.allowedOperations = mforms::DragOperationCopy;
1189
std::list<mforms::TreeNodeRef> selection = view->get_selection();
1203
Gtk::TreeModel::Path path;
1204
if(_tree.get_path_at_pos(_drag_start_x, _drag_start_y, path))
1206
Glib::RefPtr<Gdk::Pixmap> row_icon = _tree.create_row_drag_icon(path);
1208
row_icon->get_size(ico_w, ico_h);
1210
Glib::RefPtr<Gdk::Pixbuf> pix = Gdk::Pixbuf::create(row_icon->get_image(0, 0, ico_w, ico_h), 0, 0, ico_w, ico_h);
1211
//sadly we need a cairo_surface
1212
details.image = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, ico_w, ico_h);
1213
cairo_t *cr = cairo_create(details.image);
1214
gdk_cairo_set_source_pixbuf(cr, pix->gobj(), 0, 0);
1191
1218
std::string text;
1192
for (std::list<mforms::TreeNodeRef>::const_iterator iterator = selection.begin(); iterator != selection.end(); ++iterator)
1220
details.location = base::Point(ev->x, ev->y);
1221
details.allowedOperations = mforms::DragOperationCopy;
1222
if(!view->get_drag_data(details, &data, format))
1194
if (!(*iterator)->get_string(0).empty())
1196
if (text.size() > 0)
1198
text.append((*iterator)->get_string(0));
1226
std::list<mforms::TreeNodeRef> selection = view->get_selection();
1228
for (std::list<mforms::TreeNodeRef>::const_iterator iterator = selection.begin(); iterator != selection.end(); ++iterator)
1230
if (!(*iterator)->get_string(0).empty())
1232
if (text.size() > 0)
1234
text.append((*iterator)->get_string(0));
1240
cairo_surface_destroy(details.image);
1207
view->drag_finished(view->do_drag_drop(details, data, format));
1248
mforms::DragOperation operation = view->do_drag_drop(details, data, format);
1249
cairo_surface_destroy(details.image);
1251
view->drag_finished(operation);
1541
1603
tree->_conn.unblock();
1544
static int str_number_cmp(const Gtk::TreeModel::iterator& it1, const Gtk::TreeModel::iterator& it2, Gtk::TreeModelColumn< Glib::ustring> *col)
1546
double v1 = mforms::TreeNodeView::parse_string_with_unit((*it1).get_value(*col).c_str());
1547
double v2 = mforms::TreeNodeView::parse_string_with_unit((*it2).get_value(*col).c_str());
1549
return (int)(v2-v1);
1552
static int str_cmp(const Gtk::TreeModel::iterator& it1, const Gtk::TreeModel::iterator& it2, Gtk::TreeModelColumn< Glib::ustring> *col)
1554
const Glib::ustring s1 = (*it1).get_value(*col);
1555
const Glib::ustring s2 = (*it2).get_value(*col);
1557
if (s1.is_ascii() && s2.is_ascii())
1558
return strcmp(s1.c_str(), s2.c_str());
1560
return s1.compare(s2);
1606
template<typename T>
1607
int column_value_compare(const T &val1, const T &val2)
1610
if (val2 < val1) result = -1;
1611
else if (val2 > val1) result = 1;
1615
template<typename T>
1616
int column_numeric_compare(const Gtk::TreeModel::iterator& it1, const Gtk::TreeModel::iterator& it2, Gtk::TreeModelColumn<T> *col)
1618
return column_value_compare((*it1).get_value(*col), (*it2).get_value(*col));
1621
int column_string_compare(const Gtk::TreeModel::iterator& it1, const Gtk::TreeModel::iterator& it2, Gtk::TreeModelColumn<Glib::ustring> *col, int type)
1627
case StringColumnType:
1628
case StringLTColumnType:
1629
case IconColumnType:
1631
std::string val1 = (*it1).get_value(*col).c_str();
1632
std::string val2 = (*it2).get_value(*col).c_str();
1633
result = base::string_compare(val2, val1, false);
1636
case IntegerColumnType:
1637
case LongIntegerColumnType:
1639
std::istringstream ss_val1((*it1).get_value(*col).c_str());
1640
std::istringstream ss_val2((*it2).get_value(*col).c_str());
1645
result = column_value_compare(val1, val2);
1648
case FloatColumnType:
1649
case NumberWithUnitColumnType:
1651
double val1 = mforms::TreeNodeView::parse_string_with_unit((*it1).get_value(*col).c_str());
1652
double val2 = mforms::TreeNodeView::parse_string_with_unit((*it2).get_value(*col).c_str());
1653
result = column_value_compare(val1, val2);
1563
1661
void TreeNodeViewImpl::set_allow_sorting(TreeNodeView* self, bool flag)
1571
1669
if (_tree.get_headers_visible())
1572
1670
_tree.set_headers_clickable(flag);
1573
if (flag && _tree_store)
1672
if (flag == false || !_tree_store)
1676
_sort_model = Gtk::TreeModelSort::create(_tree_store);
1678
for (std::size_t i = 0; i < _tree.get_columns().size(); ++i)
1576
_sort_model = Gtk::TreeModelSort::create(_tree_store);
1578
const int ncols = _tree.get_columns().size();
1579
for (int i = 0; i < ncols; ++i)
1582
Gtk::TreeViewColumn* col = _tree.get_column(i);
1583
Gtk::TreeModelColumnBase *mcol = _columns.columns[index_for_column(i)];
1584
if (get_owner()->get_column_type(i) == NumberWithUnitColumnType)
1586
_sort_model->set_sort_func(*mcol, sigc::bind(sigc::ptr_fun(str_number_cmp), (Gtk::TreeModelColumn< Glib::ustring>*)mcol));
1588
else if (mcol->type() == G_TYPE_STRING)
1590
_sort_model->set_sort_func(*mcol, sigc::bind(sigc::ptr_fun(str_cmp), (Gtk::TreeModelColumn< Glib::ustring>*)mcol));
1597
col->signal_clicked().connect(sigc::bind(sigc::mem_fun(this, &TreeNodeViewImpl::header_clicked),mcol,col));
1601
// temporarily disable selection change signal, gtk emits it when setting model
1603
_tree.set_model(_sort_model);
1604
_conn = _tree.get_selection()->signal_changed().connect(sigc::mem_fun(dynamic_cast<TreeNodeView*>(owner), &TreeNodeView::changed));
1680
Gtk::TreeViewColumn* col = _tree.get_column(i);
1681
Gtk::TreeModelColumnBase *mcol = _columns.columns[index_for_column(i)];
1683
if (col == NULL || mcol == NULL)
1685
log_warning("Invalid column pointer[col:%s][mcol:%s]\n", col == NULL ? "NULL" : "NOT NULL", mcol == NULL ? "NULL" : "NOT NULL");
1689
col->signal_clicked().connect(sigc::bind(sigc::mem_fun(this, &TreeNodeViewImpl::header_clicked),mcol,col));
1691
// Align columns text depending on the visualization type
1694
switch(get_owner()->get_column_type(i))
1696
case StringColumnType:
1697
case StringLTColumnType:
1698
case IconColumnType:
1701
case IntegerColumnType:
1702
case LongIntegerColumnType:
1703
case FloatColumnType:
1704
case NumberWithUnitColumnType:
1707
case CheckColumnType:
1708
case TriCheckColumnType:
1713
Glib::ListHandle<Gtk::CellRenderer*> renderers = col->get_cell_renderers();
1715
for (Glib::ListHandle<Gtk::CellRenderer*>::const_iterator iter = renderers.begin(); iter != renderers.end(); ++iter)
1716
(*iter)->set_alignment(align, 0);
1718
// Set the proper compare method to the sorting functions depending on the storage type
1719
switch (mcol->type())
1722
_sort_model->set_sort_func(*mcol, sigc::bind(sigc::ptr_fun(column_numeric_compare<int>), (Gtk::TreeModelColumn<int>*)mcol));
1725
_sort_model->set_sort_func(*mcol, sigc::bind(sigc::ptr_fun(column_numeric_compare<long>), (Gtk::TreeModelColumn<long>*)mcol));
1728
_sort_model->set_sort_func(*mcol, sigc::bind(sigc::ptr_fun(column_numeric_compare<int64_t>), (Gtk::TreeModelColumn<int64_t>*)mcol));
1731
_sort_model->set_sort_func(*mcol, sigc::bind(sigc::ptr_fun(column_numeric_compare<unsigned int>), (Gtk::TreeModelColumn<unsigned int>*)mcol));
1734
_sort_model->set_sort_func(*mcol, sigc::bind(sigc::ptr_fun(column_numeric_compare<unsigned long>), (Gtk::TreeModelColumn<unsigned long>*)mcol));
1737
_sort_model->set_sort_func(*mcol, sigc::bind(sigc::ptr_fun(column_numeric_compare<uint64_t>), (Gtk::TreeModelColumn<uint64_t>*)mcol));
1741
_sort_model->set_sort_func(*mcol, sigc::bind(sigc::ptr_fun(column_numeric_compare<double>), (Gtk::TreeModelColumn<double>*)mcol));
1744
_sort_model->set_sort_func(*mcol, sigc::bind(sigc::ptr_fun(column_string_compare), (Gtk::TreeModelColumn<Glib::ustring>*)mcol, get_owner()->get_column_type(i)));
1747
log_warning("Unknown column storage type");
1752
// temporarily disable selection change signal, gtk emits it when setting model
1754
_tree.set_model(_sort_model);
1755
_conn = _tree.get_selection()->signal_changed().connect(sigc::mem_fun(dynamic_cast<TreeNodeView*>(owner), &TreeNodeView::changed));
1608
1758
void TreeNodeViewImpl::freeze_refresh(TreeNodeView* self, bool flag)