~ubuntu-branches/ubuntu/utopic/mysql-workbench/utopic

« back to all changes in this revision

Viewing changes to library/forms/gtk/src/lf_treenodeview.cpp

  • Committer: Package Import Robot
  • Author(s): Dmitry Smirnov
  • Date: 2014-05-31 12:03:58 UTC
  • mfrom: (1.2.4)
  • Revision ID: package-import@ubuntu.com-20140531120358-cjik5ofkmj0fxsn8
Tags: 6.1.6+dfsg-1
* New upstream release [May 2014].
* Dropped "prtcl.patch".
* "debian/clean": better clean-up.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1072
1072
//---------------------------------------------------------------------------------------
1073
1073
 
1074
1074
TreeNodeViewImpl::TreeNodeViewImpl(TreeNodeView *self, mforms::TreeOptions opts)
1075
 
  : ViewImpl(self), _row_height(-1)
 
1075
  : ViewImpl(self), _row_height(-1), _org_event(0)
1076
1076
{
1077
1077
  _drag_in_progress = false;
1078
1078
  _drag_button = 0;
1092
1092
  _tree.signal_test_expand_row().connect(sigc::bind_return(sigc::mem_fun(this, &TreeNodeViewImpl::on_will_expand), false));
1093
1093
  _tree.signal_button_press_event().connect(sigc::mem_fun(this, &TreeNodeViewImpl::on_button_event), false);
1094
1094
//  _tree.set_reorderable((opts & mforms::TreeAllowReorderRows) || (opts & mforms::TreeCanBeDragSource)); // we need this to have D&D working
 
1095
  _tree.signal_button_release_event().connect(sigc::mem_fun(this, &TreeNodeViewImpl::on_button_release), false);
1095
1096
  if (opts & mforms::TreeCanBeDragSource)
1096
1097
  {
1097
 
    _tree.signal_button_release_event().connect(sigc::mem_fun(this, &TreeNodeViewImpl::on_button_release), false);
 
1098
 
1098
1099
    _tree.signal_motion_notify_event().connect(sigc::mem_fun(this, &TreeNodeViewImpl::on_motion_notify), false);
1099
1100
 
1100
1101
    Gtk::Widget *w = this->get_outer();
1113
1114
  _swin.show_all();
1114
1115
  _tree.set_headers_visible((opts & mforms::TreeNoHeader) == 0);
1115
1116
}
 
1117
TreeNodeViewImpl::~TreeNodeViewImpl()
 
1118
{
 
1119
  if (_org_event)
 
1120
    delete _org_event;
 
1121
}
1116
1122
 
1117
1123
void TreeNodeViewImpl::slot_drag_end(const Glib::RefPtr<Gdk::DragContext> &context)
1118
1124
{
1119
1125
  ViewImpl::slot_drag_end(context);
1120
1126
  _drag_in_progress  = false;
1121
1127
  _drag_button = 0;
 
1128
  if (_org_event)
 
1129
  {
 
1130
    delete _org_event;
 
1131
    _org_event = 0;
 
1132
  }
1122
1133
}
1123
1134
 
1124
1135
bool TreeNodeViewImpl::slot_drag_failed(const Glib::RefPtr<Gdk::DragContext> &context,Gtk::DragResult result)
1126
1137
  bool ret_val = ViewImpl::slot_drag_failed(context, result);
1127
1138
  _drag_in_progress  = false;
1128
1139
  _drag_button = 0;
 
1140
  if (_org_event)
 
1141
  {
 
1142
    delete _org_event;
 
1143
    _org_event = 0;
 
1144
  }
1129
1145
  return ret_val;
1130
1146
 
1131
1147
}
1142
1158
  {
1143
1159
    if (w->drag_check_threshold(_drag_start_x, _drag_start_y, ev->x, ev->y))
1144
1160
    {
 
1161
      if (_org_event != 0)
 
1162
      {
 
1163
        delete _org_event;
 
1164
        _org_event = 0;
 
1165
      }
 
1166
 
 
1167
      {
 
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();
 
1175
 
 
1176
        Gtk::TreeModel::Path selpath;
 
1177
        if(_tree.get_path_at_pos(_drag_start_x, _drag_start_y, selpath))
 
1178
        {
 
1179
          bool found = false;
 
1180
          for(std::vector<Gtk::TreePath>::iterator it = path_selection.begin(); it != path_selection.end(); ++it)
 
1181
          {
 
1182
            if (selpath == *it)
 
1183
            {
 
1184
              found = true;
 
1185
              break;
 
1186
            }
 
1187
          }
 
1188
          if (!found)
 
1189
          {
 
1190
            //Old selection is invalid, we need to create new one
 
1191
            _tree.get_selection()->unselect_all();
 
1192
            _tree.get_selection()->select(selpath);
 
1193
          }
 
1194
        }
 
1195
      }
 
1196
 
 
1197
 
1145
1198
      TreeNodeView *view = dynamic_cast<TreeNodeView*>(owner);
1146
1199
      if (view)
1147
1200
      {
1148
1201
        mforms::DragDetails details;
1149
 
        void *data = NULL;
1150
 
        std::string format;
1151
 
        if(view->get_drag_data(details, &data, format))
1152
 
        {
1153
 
          std::vector<Gtk::TargetEntry> targets;
1154
 
          targets.push_back(Gtk::TargetEntry(format,Gtk::TargetFlags(0),0));
1155
 
 
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;
1160
 
          TreeNodeRef node;
1161
 
 
1162
 
          Gtk::TreeModel::Path path;
1163
 
          if(_tree.get_path_at_pos(_drag_start_x, _drag_start_y, path))
1164
 
          {
1165
 
            //let's make better drag image,
1166
 
            Glib::RefPtr<Gdk::Pixmap> row_icon = _tree.create_row_drag_icon(path);
1167
 
 
1168
 
            int ico_w, ico_h;
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);
1175
 
            cairo_paint(cr);
1176
 
 
1177
 
            mforms::DragOperation operation = view->do_drag_drop(details, data, format);
1178
 
            cairo_surface_destroy(details.image);
1179
 
            cairo_destroy(cr);
1180
 
            view->drag_finished(operation);
1181
 
 
1182
 
          }
1183
 
        }
1184
 
        else
1185
 
        {
1186
 
          details.location = base::Point(ev->x, ev->y);
1187
 
          details.allowedOperations = mforms::DragOperationCopy;
1188
 
          format = "STRING";
1189
 
          std::list<mforms::TreeNodeRef> selection = view->get_selection();
1190
 
 
 
1202
 
 
1203
        Gtk::TreeModel::Path path;
 
1204
        if(_tree.get_path_at_pos(_drag_start_x, _drag_start_y, path))
 
1205
        {
 
1206
          Glib::RefPtr<Gdk::Pixmap> row_icon = _tree.create_row_drag_icon(path);
 
1207
          int ico_w, ico_h;
 
1208
          row_icon->get_size(ico_w, ico_h);
 
1209
 
 
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);
 
1215
          cairo_paint(cr);
 
1216
 
 
1217
          void *data = NULL;
1191
1218
          std::string text;
1192
 
          for (std::list<mforms::TreeNodeRef>::const_iterator iterator = selection.begin(); iterator != selection.end(); ++iterator)
 
1219
          std::string format;
 
1220
          details.location = base::Point(ev->x, ev->y);
 
1221
          details.allowedOperations = mforms::DragOperationCopy;
 
1222
          if(!view->get_drag_data(details, &data, format))
1193
1223
          {
1194
 
                if (!(*iterator)->get_string(0).empty())
1195
 
                {
1196
 
                  if (text.size() > 0)
1197
 
                    text.append(", ");
1198
 
                  text.append((*iterator)->get_string(0));
1199
 
                }
 
1224
 
 
1225
            format = "STRING";
 
1226
            std::list<mforms::TreeNodeRef> selection = view->get_selection();
 
1227
 
 
1228
            for (std::list<mforms::TreeNodeRef>::const_iterator iterator = selection.begin(); iterator != selection.end(); ++iterator)
 
1229
            {
 
1230
                  if (!(*iterator)->get_string(0).empty())
 
1231
                  {
 
1232
                    if (text.size() > 0)
 
1233
                      text.append(", ");
 
1234
                    text.append((*iterator)->get_string(0));
 
1235
                  }
 
1236
            }
 
1237
 
 
1238
            if (text.empty())
 
1239
            {
 
1240
              cairo_surface_destroy(details.image);
 
1241
              cairo_destroy(cr);
 
1242
              return false;
 
1243
            }
 
1244
 
 
1245
            data = &text;
1200
1246
          }
1201
1247
 
1202
 
          if (text.empty())
1203
 
            return false;
1204
 
 
1205
 
          data = &text;
1206
 
 
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);
 
1250
          cairo_destroy(cr);
 
1251
          view->drag_finished(operation);
1208
1252
        }
1209
1253
      }
1210
1254
    }
1219
1263
    return false;
1220
1264
  }
1221
1265
 
 
1266
  //Because of problems when Treeview has been set to multiselect,
 
1267
  //there are some DnD problems, below code is fixing those.
 
1268
  //we need this to emit press event again cause we're changing default behavior of it
 
1269
  if (_org_event != 0)
 
1270
  {
 
1271
    gtk_propagate_event((GtkWidget*)_tree.gobj(), (GdkEvent*)_org_event);
 
1272
    delete _org_event;
 
1273
    _org_event = 0;
 
1274
  }
 
1275
//  _tree.
1222
1276
  _drag_button = 0;
1223
1277
  return false;
1224
1278
}
1235
1289
{
1236
1290
  if (!force_sys_colors)
1237
1291
  {
1238
 
    Gdk::Color col(color);
1239
 
    _tree.get_colormap()->alloc_color(col);
1240
 
    _tree.modify_base(Gtk::STATE_NORMAL, col);
 
1292
    if (!color.empty())
 
1293
    {
 
1294
      Gdk::Color col(color);
 
1295
      _tree.get_colormap()->alloc_color(col);
 
1296
      _tree.modify_base(Gtk::STATE_NORMAL, col);
 
1297
    }
1241
1298
  }
1242
1299
}
1243
1300
 
1327
1384
  }
1328
1385
  else if (event->button == 1 && _drag_button == 0)
1329
1386
  {
1330
 
    _drag_button = event->button;
1331
 
    _drag_start_x = event->x;
1332
 
    _drag_start_y = event->y;
 
1387
    if (_org_event == 0)
 
1388
    {
 
1389
      _org_event = new GdkEventButton(*event);
 
1390
      _drag_button = event->button;
 
1391
      _drag_start_x = event->x;
 
1392
      _drag_start_y = event->y;
 
1393
      ret_val = true;
 
1394
    }
1333
1395
  }
1334
1396
 
1335
1397
  
1541
1603
  tree->_conn.unblock();
1542
1604
}
1543
1605
 
1544
 
static int str_number_cmp(const Gtk::TreeModel::iterator& it1, const Gtk::TreeModel::iterator& it2, Gtk::TreeModelColumn< Glib::ustring> *col)
1545
 
{
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());
1548
 
 
1549
 
  return (int)(v2-v1);
1550
 
}
1551
 
 
1552
 
static int str_cmp(const Gtk::TreeModel::iterator& it1, const Gtk::TreeModel::iterator& it2, Gtk::TreeModelColumn< Glib::ustring> *col)
1553
 
{
1554
 
  const Glib::ustring s1 = (*it1).get_value(*col);
1555
 
  const Glib::ustring s2 = (*it2).get_value(*col);
1556
 
 
1557
 
  if (s1.is_ascii() && s2.is_ascii())
1558
 
    return strcmp(s1.c_str(), s2.c_str());
1559
 
  else
1560
 
    return s1.compare(s2);
 
1606
template<typename T>
 
1607
int column_value_compare(const T &val1, const T &val2)
 
1608
{
 
1609
  int result = 0;
 
1610
  if (val2 < val1) result = -1;
 
1611
  else if (val2 > val1) result = 1;
 
1612
  return result;
 
1613
}
 
1614
 
 
1615
template<typename T>
 
1616
int column_numeric_compare(const Gtk::TreeModel::iterator& it1, const Gtk::TreeModel::iterator& it2, Gtk::TreeModelColumn<T> *col)
 
1617
{
 
1618
  return column_value_compare((*it1).get_value(*col), (*it2).get_value(*col));
 
1619
}
 
1620
 
 
1621
int column_string_compare(const Gtk::TreeModel::iterator& it1, const Gtk::TreeModel::iterator& it2, Gtk::TreeModelColumn<Glib::ustring> *col, int type)
 
1622
{
 
1623
  int result = 0;
 
1624
  
 
1625
  switch (type)
 
1626
  {
 
1627
    case StringColumnType:
 
1628
    case StringLTColumnType:
 
1629
    case IconColumnType:
 
1630
    {
 
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);
 
1634
      break;
 
1635
    }
 
1636
    case IntegerColumnType:
 
1637
    case LongIntegerColumnType:
 
1638
    {
 
1639
      std::istringstream ss_val1((*it1).get_value(*col).c_str());
 
1640
      std::istringstream ss_val2((*it2).get_value(*col).c_str());
 
1641
      int64_t val1 = 0;
 
1642
      int64_t val2 = 0;
 
1643
      ss_val1 >> val1;
 
1644
      ss_val2 >> val2;
 
1645
      result = column_value_compare(val1, val2);
 
1646
      break;
 
1647
    }
 
1648
    case FloatColumnType:
 
1649
    case NumberWithUnitColumnType:
 
1650
    {
 
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);
 
1654
      break;
 
1655
    }
 
1656
  }
 
1657
  
 
1658
  return result;
1561
1659
}
1562
1660
 
1563
1661
void TreeNodeViewImpl::set_allow_sorting(TreeNodeView* self, bool flag)
1570
1668
{
1571
1669
  if (_tree.get_headers_visible())
1572
1670
    _tree.set_headers_clickable(flag);
1573
 
  if (flag && _tree_store)
 
1671
  
 
1672
  if (flag == false || !_tree_store)
 
1673
    return;
 
1674
    
 
1675
  if (!_sort_model)
 
1676
    _sort_model = Gtk::TreeModelSort::create(_tree_store);
 
1677
 
 
1678
  for (std::size_t i = 0; i < _tree.get_columns().size(); ++i)
1574
1679
  {
1575
 
    if (!_sort_model)
1576
 
      _sort_model = Gtk::TreeModelSort::create(_tree_store);
1577
 
 
1578
 
    const int ncols = _tree.get_columns().size();
1579
 
    for (int i = 0; i < ncols; ++i)
1580
 
    {
1581
 
 
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)
1585
 
      {
1586
 
        _sort_model->set_sort_func(*mcol, sigc::bind(sigc::ptr_fun(str_number_cmp), (Gtk::TreeModelColumn< Glib::ustring>*)mcol));
1587
 
      }
1588
 
      else if (mcol->type() == G_TYPE_STRING)
1589
 
      {
1590
 
        _sort_model->set_sort_func(*mcol, sigc::bind(sigc::ptr_fun(str_cmp), (Gtk::TreeModelColumn< Glib::ustring>*)mcol));
1591
 
      }
1592
 
 
1593
 
 
1594
 
 
1595
 
      if (mcol && col)
1596
 
      {
1597
 
        col->signal_clicked().connect(sigc::bind(sigc::mem_fun(this, &TreeNodeViewImpl::header_clicked),mcol,col));
1598
 
      }
1599
 
    }
1600
 
 
1601
 
    // temporarily disable selection change signal, gtk emits it when setting model
1602
 
    _conn.disconnect();
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)];
 
1682
    
 
1683
    if (col == NULL || mcol == NULL)
 
1684
    {
 
1685
      log_warning("Invalid column pointer[col:%s][mcol:%s]\n", col == NULL ? "NULL" : "NOT NULL", mcol == NULL ? "NULL" : "NOT NULL");
 
1686
      continue;
 
1687
    }
 
1688
 
 
1689
    col->signal_clicked().connect(sigc::bind(sigc::mem_fun(this, &TreeNodeViewImpl::header_clicked),mcol,col));
 
1690
    
 
1691
    //  Align columns text depending on the visualization type
 
1692
    float align = 0.0f;
 
1693
    
 
1694
    switch(get_owner()->get_column_type(i))
 
1695
    {
 
1696
      case StringColumnType:
 
1697
      case StringLTColumnType:
 
1698
      case IconColumnType:
 
1699
        align = 0.0f;
 
1700
        break;
 
1701
      case IntegerColumnType:
 
1702
      case LongIntegerColumnType:
 
1703
      case FloatColumnType:
 
1704
      case NumberWithUnitColumnType:
 
1705
        align = 1.0f;
 
1706
        break;
 
1707
      case CheckColumnType:
 
1708
      case TriCheckColumnType:
 
1709
        align = 0.5f;
 
1710
        break;
 
1711
    }      
 
1712
    
 
1713
    Glib::ListHandle<Gtk::CellRenderer*> renderers = col->get_cell_renderers();
 
1714
    
 
1715
    for (Glib::ListHandle<Gtk::CellRenderer*>::const_iterator iter = renderers.begin(); iter != renderers.end(); ++iter)
 
1716
      (*iter)->set_alignment(align, 0);
 
1717
    
 
1718
    //  Set the proper compare method to the sorting functions depending on the storage type
 
1719
    switch (mcol->type())
 
1720
    {
 
1721
      case G_TYPE_INT:
 
1722
        _sort_model->set_sort_func(*mcol, sigc::bind(sigc::ptr_fun(column_numeric_compare<int>), (Gtk::TreeModelColumn<int>*)mcol));
 
1723
        break;
 
1724
      case G_TYPE_LONG:
 
1725
        _sort_model->set_sort_func(*mcol, sigc::bind(sigc::ptr_fun(column_numeric_compare<long>), (Gtk::TreeModelColumn<long>*)mcol));
 
1726
        break;
 
1727
      case G_TYPE_INT64:
 
1728
        _sort_model->set_sort_func(*mcol, sigc::bind(sigc::ptr_fun(column_numeric_compare<int64_t>), (Gtk::TreeModelColumn<int64_t>*)mcol));
 
1729
        break;
 
1730
      case G_TYPE_UINT:
 
1731
        _sort_model->set_sort_func(*mcol, sigc::bind(sigc::ptr_fun(column_numeric_compare<unsigned int>), (Gtk::TreeModelColumn<unsigned int>*)mcol));
 
1732
        break;
 
1733
      case G_TYPE_ULONG:
 
1734
        _sort_model->set_sort_func(*mcol, sigc::bind(sigc::ptr_fun(column_numeric_compare<unsigned long>), (Gtk::TreeModelColumn<unsigned long>*)mcol));
 
1735
        break;
 
1736
      case G_TYPE_UINT64:
 
1737
        _sort_model->set_sort_func(*mcol, sigc::bind(sigc::ptr_fun(column_numeric_compare<uint64_t>), (Gtk::TreeModelColumn<uint64_t>*)mcol));
 
1738
        break;
 
1739
      case G_TYPE_FLOAT:
 
1740
      case G_TYPE_DOUBLE:
 
1741
        _sort_model->set_sort_func(*mcol, sigc::bind(sigc::ptr_fun(column_numeric_compare<double>), (Gtk::TreeModelColumn<double>*)mcol));
 
1742
        break;
 
1743
      case G_TYPE_STRING:
 
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)));
 
1745
        break;
 
1746
      default:
 
1747
        log_warning("Unknown column storage type");
 
1748
        break;
 
1749
    }
1605
1750
  }
 
1751
 
 
1752
  // temporarily disable selection change signal, gtk emits it when setting model
 
1753
  _conn.disconnect();
 
1754
  _tree.set_model(_sort_model);
 
1755
  _conn = _tree.get_selection()->signal_changed().connect(sigc::mem_fun(dynamic_cast<TreeNodeView*>(owner), &TreeNodeView::changed));
1606
1756
}
1607
1757
 
1608
1758
void TreeNodeViewImpl::freeze_refresh(TreeNodeView* self, bool flag)