26 #include <yui/gtk/YGi18n.h> 28 #define YUILogComponent "mga-gtk-ui" 30 #include <yui/YUILog.h> 31 #include <yui/gtk/YGUI.h> 32 #include <yui/gtk/YGUtils.h> 33 #include <yui/gtk/YGWidget.h> 34 #include <YSelectionWidget.h> 35 #include <yui/gtk/YGSelectionStore.h> 36 #include <yui/gtk/ygtktreeview.h> 38 #include <yui/mga/YMGA_CBTable.h> 41 #include <yui/gtk/YGDialog.h> 42 #include <gdk/gdkkeysyms.h> 44 #include "YMGA_GCBTable.h" 48 YMGA_GTreeView::YMGA_GTreeView (YWidget *ywidget, YWidget *parent,
const std::string &label,
bool tree)
49 : YGScrolledWidget (ywidget, parent, label, YD_VERT, YGTK_TYPE_TREE_VIEW, NULL),
50 YGSelectionStore (tree)
52 gtk_tree_view_set_headers_visible (getView(), FALSE);
57 gtk_tree_selection_set_mode (getSelection(), GTK_SELECTION_BROWSE);
59 connect (getSelection(),
"changed", G_CALLBACK (selection_changed_cb),
this);
60 connect (getWidget(),
"row-activated", G_CALLBACK (activated_cb),
this);
61 connect (getWidget(),
"right-click", G_CALLBACK (right_click_cb),
this);
67 g_signal_connect (getWidget(),
"map", G_CALLBACK (block_init_cb),
this);
70 YMGA_GTreeView::~YMGA_GTreeView()
72 if (m_blockTimeout) g_source_remove (m_blockTimeout);
75 void YMGA_GTreeView::addTextColumn (
int iconCol,
int textCol)
77 addTextColumn (
"", YAlignUnchanged, iconCol, textCol);
80 void YMGA_GTreeView::addTextColumn (
const std::string &header, YAlignmentType align,
int icon_col,
int text_col)
97 GtkTreeViewColumn *column = gtk_tree_view_column_new();
98 gtk_tree_view_column_set_title (column, header.c_str());
100 GtkCellRenderer *renderer;
101 renderer = gtk_cell_renderer_pixbuf_new();
102 gtk_tree_view_column_pack_start (column, renderer, FALSE);
103 gtk_tree_view_column_set_attributes (column, renderer,
"pixbuf", icon_col, NULL);
105 renderer = gtk_cell_renderer_text_new();
106 gtk_tree_view_column_pack_start (column, renderer, TRUE);
107 gtk_tree_view_column_set_attributes (column, renderer,
"text", text_col, NULL);
109 g_object_set (renderer,
"xalign", xalign, NULL);
111 gtk_tree_view_column_set_resizable (column, TRUE);
112 gtk_tree_view_append_column (getView(), column);
113 if (gtk_tree_view_get_search_column (getView()) == -1)
114 gtk_tree_view_set_search_column (getView(), text_col);
117 void YMGA_GTreeView::addCheckColumn (
int check_col)
119 addCheckColumn (
"", check_col);
122 void YMGA_GTreeView::addCheckColumn (
const std::string &header,
int check_col)
124 GtkCellRenderer *renderer = gtk_cell_renderer_toggle_new();
125 g_object_set_data (G_OBJECT (renderer),
"column", GINT_TO_POINTER (check_col));
126 GtkTreeViewColumn *column = gtk_tree_view_column_new_with_attributes (
127 NULL, renderer,
"active", check_col, NULL);
129 gtk_tree_view_column_set_title (column, header.c_str());
131 gtk_tree_view_column_set_cell_data_func (column, renderer, inconsistent_mark_cb,
this, NULL);
132 g_signal_connect (G_OBJECT (renderer),
"toggled",
133 G_CALLBACK (toggled_cb),
this);
135 gtk_tree_view_column_set_resizable (column, TRUE);
136 gtk_tree_view_append_column (getView(), column);
137 if (markColumn == -1)
138 markColumn = check_col;
141 void YMGA_GTreeView::readModel()
143 gtk_tree_view_set_model (getView(), getModel());
146 void YMGA_GTreeView::addCountWidget (YWidget *yparent)
148 bool mainWidget = !yparent || !strcmp (yparent->widgetClass(),
"YVBox") || !strcmp (yparent->widgetClass(),
"YReplacePoint");
150 m_count = gtk_label_new (
"0");
151 GtkWidget *hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4);
152 gtk_box_set_homogeneous (GTK_BOX (hbox), FALSE);
154 GtkWidget *label = gtk_label_new (_(
"Total selected:"));
156 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 0);
157 gtk_box_pack_start (GTK_BOX (hbox), m_count, FALSE, TRUE, 0);
158 gtk_box_pack_start (GTK_BOX (YGWidget::getWidget()), hbox, FALSE, TRUE, 0);
159 gtk_widget_show_all (hbox);
163 void YMGA_GTreeView::syncCount()
165 if (!m_count)
return;
168 static gboolean
foreach (
169 GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer _pThis)
173 gtk_tree_model_get (model, iter, pThis->markColumn, &mark, -1);
175 int count = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (model),
"count"));
176 g_object_set_data (G_OBJECT (model),
"count", GINT_TO_POINTER (count+1));
182 GtkTreeModel *model = getModel();
183 g_object_set_data (G_OBJECT (model),
"count", 0);
184 gtk_tree_model_foreach (model, inner::foreach,
this);
186 int count = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (model),
"count"));
187 gchar *str = g_strdup_printf (
"%d", count);
188 gtk_label_set_text (GTK_LABEL (m_count), str);
192 void YMGA_GTreeView::focusItem (YItem *item,
bool select)
195 getTreeIter (item, &iter);
199 GtkTreePath *path = gtk_tree_model_get_path (getModel(), &iter);
200 gtk_tree_view_expand_to_path (getView(), path);
202 if (gtk_tree_selection_get_mode (getSelection()) != GTK_SELECTION_MULTIPLE)
203 gtk_tree_view_scroll_to_cell (getView(), path, NULL, TRUE, 0.5, 0);
204 gtk_tree_path_free (path);
206 gtk_tree_selection_select_iter (getSelection(), &iter);
209 gtk_tree_selection_unselect_iter (getSelection(), &iter);
212 void YMGA_GTreeView::unfocusAllItems()
215 gtk_tree_selection_unselect_all (getSelection());
218 void YMGA_GTreeView::unmarkAll()
221 static gboolean foreach_unmark (
222 GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer _pThis)
225 pThis->setRowMark (iter, pThis->markColumn, FALSE);
230 gtk_tree_model_foreach (getModel(), inner::foreach_unmark,
this);
233 YItem *YMGA_GTreeView::getFocusItem()
236 if (gtk_tree_selection_get_selected (getSelection(), NULL, &iter))
237 return getYItem (&iter);
242 void YMGA_GTreeView::setMark (GtkTreeIter *iter, YItem *yitem, gint column,
bool state,
bool recursive)
244 setRowMark (iter, column, state);
245 yitem->setSelected (state);
248 for (YItemConstIterator it = yitem->childrenBegin();
249 it != yitem->childrenEnd(); it++) {
251 getTreeIter (*it, &_iter);
252 setMark (&_iter, *it, column, state,
true);
256 void YMGA_GTreeView::toggleMark (GtkTreePath *path, gint column)
259 if (!gtk_tree_model_get_iter (getModel(), &iter, path))
262 gtk_tree_model_get (getModel(), &iter, column, &state, -1);
265 YItem *yitem = getYItem (&iter);
266 YCBTableItem *pYCBTableItem =
dynamic_cast<YCBTableItem*
>(yitem);
269 YMGA_CBTable * pTable =
dynamic_cast<YMGA_CBTable*
>(
this);
272 if ( (pTable->tableMode() == YCBTableMode::YCBTableCheckBoxOnFirstColumn && column == 0)
274 (pTable->tableMode() == YCBTableMode::YCBTableCheckBoxOnLastColumn && column == (pTable->columns()-1)*3 ))
276 setRowMark (&iter, column, state);
277 pYCBTableItem->check(state);
278 pTable->setChangedItem(pYCBTableItem);
279 emitEvent (YEvent::ValueChanged);
285 setMark (&iter, yitem, column, state, _recursiveSelection());
287 emitEvent (YEvent::ValueChanged);
291 unsigned int YMGA_GTreeView::getMinSize (YUIDimension dim)
294 return YGUtils::getCharsHeight (getWidget(), _shrinkable() ? 2 : 5);
298 gboolean YMGA_GTreeView::block_selected_timeout_cb (gpointer data)
301 pThis->m_blockTimeout = 0;
305 void YMGA_GTreeView::blockSelected()
307 if (m_blockTimeout) g_source_remove (m_blockTimeout);
308 m_blockTimeout = g_timeout_add_full (G_PRIORITY_LOW, 50, block_selected_timeout_cb,
this, NULL);
311 void YMGA_GTreeView::block_init_cb (GtkWidget *widget,
YMGA_GTreeView *pThis)
313 pThis->blockSelected();
318 bool YMGA_GTreeView::all_marked (GtkTreeModel *model, GtkTreeIter *iter,
int mark_col)
321 GtkTreeIter child_iter;
322 if (gtk_tree_model_iter_children (model, &child_iter, iter))
324 gtk_tree_model_get (model, &child_iter, mark_col, &marked, -1);
325 if (!marked)
return false;
326 all_marked (model, &child_iter, mark_col);
327 }
while (gtk_tree_model_iter_next (model, &child_iter));
331 void YMGA_GTreeView::inconsistent_mark_cb (GtkTreeViewColumn *column,
332 GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
336 gtk_tree_model_get (model, iter, pThis->markColumn, &marked, -1);
337 gboolean consistent = !marked || all_marked (model, iter, pThis->markColumn);
338 g_object_set (G_OBJECT (cell),
"inconsistent", !consistent, NULL);
341 void YMGA_GTreeView::selection_changed_cb (GtkTreeSelection *selection,
YMGA_GTreeView *pThis)
344 static gboolean foreach_sync_select (
345 GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer _pThis)
348 GtkTreeSelection *selection = pThis->getSelection();
349 bool sel = gtk_tree_selection_iter_is_selected (selection, iter);
350 pThis->getYItem (iter)->setSelected (sel);
355 if (pThis->m_blockTimeout)
return;
356 gtk_tree_model_foreach (pThis->getModel(), inner::foreach_sync_select, pThis);
357 if (pThis->_immediateMode())
358 pThis->emitEvent (YEvent::SelectionChanged, IF_NOT_PENDING_EVENT);
361 void YMGA_GTreeView::activated_cb (GtkTreeView *tree_view, GtkTreePath *path,
364 YMGA_CBTable *pTable =
dynamic_cast<YMGA_CBTable*
>(pThis);
367 GtkTreeViewColumn* col = gtk_tree_view_get_column (pThis->getView(), pThis->markColumn);
369 pThis->toggleMark (path, pThis->markColumn);
373 if ( gtk_tree_view_row_expanded ( tree_view, path ) )
374 gtk_tree_view_collapse_row ( tree_view, path );
376 gtk_tree_view_expand_row ( tree_view, path, FALSE );
378 pThis->emitEvent ( YEvent::Activated );
382 pThis->toggleMark (path, pThis->markColumn);
385 void YMGA_GTreeView::toggled_cb (GtkCellRendererToggle *renderer, gchar *path_str,
388 GtkTreePath *path = gtk_tree_path_new_from_string (path_str);
389 gint column = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (renderer),
"column"));
390 pThis->toggleMark (path, column);
391 gtk_tree_path_free (path);
394 if (gtk_tree_path_get_depth (path) >= 2)
395 gtk_widget_queue_draw (pThis->getWidget());
398 void YMGA_GTreeView::right_click_cb (YGtkTreeView *view, gboolean outreach,
YMGA_GTreeView *pThis)
400 pThis->emitEvent (YEvent::ContextMenuActivated);
406 YMGA_GCBTable::YMGA_GCBTable (YWidget *parent, YTableHeader *headers, YCBTableMode mode)
407 : YMGA_CBTable (NULL, headers, mode),
410 gtk_tree_view_set_headers_visible (getView(), TRUE);
411 gtk_tree_view_set_rules_hint (getView(), columns() > 1);
412 ygtk_tree_view_set_empty_text (YGTK_TREE_VIEW (getView()), _(
"No entries."));
413 int columnNumber = columns();
415 yuiMilestone() <<
" Slection mode " << mode << std::endl;
417 GType types [columnNumber*3];
418 for (
int i = 0; i < columnNumber; i++) {
420 types[t+0] = G_TYPE_BOOLEAN;
421 types[t+1] = GDK_TYPE_PIXBUF;
422 types[t+2] = G_TYPE_STRING;
423 if ( (i==0 && mode == YCBTableCheckBoxOnFirstColumn) ||
424 (i == columnNumber-1 && mode == YCBTableCheckBoxOnLastColumn))
425 addCheckColumn(header(i), t);
427 addTextColumn (header(i), alignment (i), t+1, t+2);
429 createStore (columnNumber*3, types);
434 yuiMilestone() <<
" columns " << columns() <<
" tot " << columnNumber << std::endl;
437 YAlignmentType lastAlign = alignment (columnNumber-1);
438 if (lastAlign == YAlignCenter || lastAlign == YAlignEnd)
439 gtk_tree_view_append_column (getView(), gtk_tree_view_column_new());
441 g_signal_connect (getWidget(),
"key-press-event", G_CALLBACK (key_press_event_cb),
this);
444 void YMGA_GCBTable::setSortable (
bool sortable)
446 if (!sortable && !gtk_widget_get_realized (getWidget()))
449 GList *columns = gtk_tree_view_get_columns (getView());
450 int mode = tableMode();
451 int columnNumber = YMGA_GCBTable::columns();
452 for (GList *i = columns; i; i = i->next, n++) {
453 GtkTreeViewColumn *column = (GtkTreeViewColumn *) i->data;
454 if (n >= columnNumber)
459 if (! ( (n==0 && mode == YCBTableCheckBoxOnFirstColumn) ||
460 (n == columnNumber-1 && mode == YCBTableCheckBoxOnLastColumn)))
462 gtk_tree_sortable_set_sort_func (
463 GTK_TREE_SORTABLE (getModel()), index, tree_sort_cb,
464 GINT_TO_POINTER (index), NULL);
465 gtk_tree_view_column_set_sort_column_id (column, index);
469 gtk_tree_view_column_set_sort_column_id (column, -1);
471 g_list_free (columns);
474 void YMGA_GCBTable::setCell (GtkTreeIter *iter,
int column,
const YTableCell *cell)
477 std::string label (cell->label());
479 int index = column * 3;
480 setRowText (iter, index+1, cell->iconName(), index+2, label,
this);
485 bool YMGA_GCBTable::_immediateMode() {
486 return immediateMode();
491 void YMGA_GCBTable::setKeepSorting (
bool keepSorting)
493 YMGA_CBTable::setKeepSorting (keepSorting);
494 setSortable (!keepSorting);
496 GtkTreeViewColumn *column = gtk_tree_view_get_column (getView(), 0);
498 gtk_tree_view_column_clicked (column);
502 void YMGA_GCBTable::cellChanged (
const YTableCell *cell)
505 getTreeIter (cell->parent(), &iter);
506 int mode = tableMode();
507 int column = (mode == YCBTableCheckBoxOnLastColumn ? cell->column() : cell->column() +1);
508 setCell (&iter, column, cell);
511 void YMGA_GCBTable::doAddItem (YItem *_item)
513 YCBTableItem *item = dynamic_cast <YCBTableItem *> (_item);
516 addRow (item, &iter);
518 if (tableMode() == YCBTableMode::YCBTableCheckBoxOnFirstColumn )
520 setRowMark(&iter, i++, item->checked());
522 for (YTableCellIterator it = item->cellsBegin();
523 it != item->cellsEnd(); it++)
527 yuiWarning() <<
"Item contains too many columns, current is " << i
528 <<
" but only " << columns() <<
" columns are configured" << std::endl;
531 setCell (&iter, i++, *it);
533 if (tableMode() == YCBTableMode::YCBTableCheckBoxOnLastColumn )
535 int col = columns() -1;
536 setRowMark(&iter, col*3, item->checked());
538 if (item->selected())
539 focusItem (item,
true);
542 yuiError() <<
"Can only add YCBTableItems to a YTable.\n";
545 void YMGA_GCBTable::checkItem ( YItem* item,
bool checked )
548 YCBTableItem *pItem = dynamic_cast <YCBTableItem *> (item);
550 getTreeIter ( item, &iter );
552 setRowMark ( &iter, markColumn, checked );
553 pItem->check(checked);
556 void YMGA_GCBTable::doSelectItem (YItem *item,
bool select)
558 focusItem (item, select);
561 void YMGA_GCBTable::doDeselectAllItems()
568 void YMGA_GCBTable::activateButton (YWidget *button)
570 YWidgetEvent *
event =
new YWidgetEvent (button, YEvent::Activated);
571 YGUI::ui()->sendEvent (event);
574 void YMGA_GCBTable::hack_right_click_cb (YGtkTreeView* view, gboolean outreach,
YMGA_GCBTable* pThis)
576 if (pThis->notifyContextMenu())
577 return YMGA_GTreeView::right_click_cb (view, outreach, pThis);
582 static void key_activate_cb (GtkMenuItem *item, YWidget *button)
584 activateButton (button);
586 static void appendItem (GtkWidget *menu,
const gchar *stock,
int key)
588 YWidget *button = YGDialog::currentDialog()->getFunctionWidget (key);
591 item = gtk_menu_item_new_with_mnemonic (stock);
592 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
593 g_signal_connect (G_OBJECT (item),
"activate",
594 G_CALLBACK (key_activate_cb), button);
599 GtkWidget *menu = gtk_menu_new();
600 YGDialog *dialog = YGDialog::currentDialog();
601 if (dialog->getClassWidgets (
"YTable").size() == 1) {
603 if (dialog->getClassWidgets (
"YTable").size() == 1) {
606 if (dialog->getFunctionWidget(3))
607 inner::appendItem (menu,
"list-add", 3);
610 if (dialog->getFunctionWidget(4))
611 inner::appendItem (menu,
"edit-cut", 4);
612 if (dialog->getFunctionWidget(5))
613 inner::appendItem (menu,
"list-remove", 5);
618 menu = ygtk_tree_view_append_show_columns_item (YGTK_TREE_VIEW (view), menu);
619 ygtk_tree_view_popup_menu (view, menu);
622 gboolean YMGA_GCBTable::key_press_event_cb (GtkWidget* widget, GdkEventKey* event,
YMGA_GCBTable* pThis)
624 if (event->keyval == GDK_KEY_Delete) {
625 YWidget *button = YGDialog::currentDialog()->getFunctionWidget (5);
627 activateButton (button);
629 gtk_widget_error_bell (widget);
635 gint YMGA_GCBTable::tree_sort_cb (
636 GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer _index)
638 int index = GPOINTER_TO_INT (_index);
639 gchar *str_a, *str_b;
640 gtk_tree_model_get (model, a, index, &str_a, -1);
641 gtk_tree_model_get (model, b, index, &str_b, -1);
642 if (!str_a) str_a = g_strdup (
"");
643 if (!str_b) str_b = g_strdup (
"");
644 int ret = strcmp (str_a, str_b);