1 { $Id$
2
3 *****************************************************************************
4 This file is part of the Lazarus Component Library (LCL)
5
6 See the file COPYING.modifiedLGPL.txt, included in this distribution,
7 for details about the license.
8 *****************************************************************************
9 }
10
11 unit Gtk2ListViewTreeModel;
12
13 {$mode objfpc}{$H+}
14
15 interface
16
17 uses
18 // FPC
19 Classes, SysUtils,
20 // Gtk
21 gtk2, glib2,
22 // LCL
23 ComCtrls;
24 const
25 ELCLListViewModel = 'LCLListViewModel';
26 type
27
28 { TLCLTreeModel }
29 PLCLListViewModel = ^TLCLListViewModel;
30
31 { TLCLListViewModel }
32
33 TLCLListViewModel = object
34 {%REGION GObject} // Add nothing in or before this region!!
35 g_type_instance : TGTypeInstance;
36 ref_count : guint;
37 qdata : PGData;
38 {%ENDREGION}
39 {%REGION Interface methods in order!}
40 procedure row_changed({%H-}path:PGtkTreePath; {%H-}iter:PGtkTreeIter); cdecl;
41 procedure row_inserted({%H-}path:PGtkTreePath; {%H-}iter:PGtkTreeIter); cdecl;
42 procedure row_has_child_toggled({%H-}path:PGtkTreePath; {%H-}iter:PGtkTreeIter); cdecl;
43 procedure row_deleted({%H-}path:PGtkTreePath); cdecl;
44 procedure rows_reordered({%H-}path:PGtkTreePath; {%H-}iter:PGtkTreeIter; {%H-}new_order:Pgint); cdecl;
get_flagsnull45 function get_flags():TGtkTreeModelFlags; cdecl;
get_n_columnsnull46 function get_n_columns():gint; cdecl;
get_column_typenull47 function get_column_type({%H-}index:gint):GType; cdecl;
get_iternull48 function get_iter(iter:PGtkTreeIter; path:PGtkTreePath):gboolean; cdecl;
get_pathnull49 function get_path(iter:PGtkTreeIter):PGtkTreePath; cdecl;
50 procedure get_value(iter:PGtkTreeIter; {%H-}column:gint; value:PGValue); cdecl;
iter_nextnull51 function iter_next(iter:PGtkTreeIter):gboolean; cdecl;
iter_childrennull52 function iter_children({%H-}iter:PGtkTreeIter; {%H-}parent:PGtkTreeIter):gboolean; cdecl;
iter_has_childnull53 function iter_has_child({%H-}iter:PGtkTreeIter):gboolean; cdecl;
iter_n_childrennull54 function iter_n_children(iter:PGtkTreeIter):gint; cdecl;
iter_nth_childnull55 function iter_nth_child(iter:PGtkTreeIter; parent:PGtkTreeIter; n:gint):gboolean; cdecl;
iter_parentnull56 function iter_parent({%H-}iter:PGtkTreeIter; {%H-}child:PGtkTreeIter):gboolean; cdecl;
57 procedure ref_node({%H-}iter:PGtkTreeIter); cdecl;
58 procedure unref_node({%H-}iter:PGtkTreeIter); cdecl;
59 {%ENDREGION}
60 procedure NotifyRowInserted(AIndex: PtrUInt);
61 procedure NotifyRowDeleted(AIndex: PtrUInt);
TreeModelnull62 function TreeModel: PGtkTreeModel; inline;
63 public
64 ListView: TCustomListView;
65 end;
66
67 PMyTreeModelObjectClass = ^TLCLTreeModelClass;
68 TLCLTreeModelClass = record
69 parent_class: TGObjectClass;
70 end;
71 TLVItemHack = class(TListItem)
72 end;
73
74
LCLListViewModelNewnull75 function LCLListViewModelNew(AListView: TCustomListView): PLCLListViewModel;
LCLLISTVIEW_MODEL_TYPEnull76 function LCLLISTVIEW_MODEL_TYPE: GType;
77
78
79 procedure LCLListViewModelClassInit({%H-}g_class:gpointer; {%H-}class_data:gpointer); cdecl;
80 procedure LCLListViewModelInit({%H-}instance:PGTypeInstance; {%H-}g_class:gpointer); cdecl;
81 procedure LCLListViewModelInterfaceInit(g_iface:PGtkTreeModelIface; {%H-}iface_data:gpointer); cdecl;
82
83
84 implementation
85
86 var
87 _LCLLISTVIEW_MODEL_TYPE: gulong = 0;
88
LCLListViewModelNewnull89 function LCLListViewModelNew(AListView: TCustomListView): PLCLListViewModel;
90 begin
91 Result := g_object_new(LCLLISTVIEW_MODEL_TYPE, nil);
92 Result^.ListView := AListView;
93 end;
94
LCLLISTVIEW_MODEL_TYPEnull95 function LCLLISTVIEW_MODEL_TYPE: GType;
96 var
97 TypeInfo: TGTypeInfo;
98 INterfaceINfo: TGInterfaceInfo;
99 begin
100 _LCLLISTVIEW_MODEL_TYPE := g_type_from_name(ELCLListViewModel);
101 if _LCLLISTVIEW_MODEL_TYPE = 0 then
102 begin
103 with TypeInfo do
104 begin
105 class_size:= SizeOf(TLCLTreeModelClass);
106 base_init := nil;//TGBaseInitFunc;
107 base_finalize:= nil;// TGBaseFinalizeFunc;
108 class_init := @LCLListViewModelClassInit;// TGClassInitFunc;
109 class_finalize := nil;// TGClassFinalizeFunc;
110 class_data := nil;// gconstpointer;
111 instance_size := SizeOf(TLCLListViewModel);// guint16;
112 n_preallocs := 0;// guint16;
113 instance_init := @LCLListViewModelInit;// TGInstanceInitFunc;
114 value_table := nil;// PGTypeValueTable;
115 end;
116 with InterfaceInfo do
117 begin
118 interface_init := TGInterfaceInitFunc(@LCLListViewModelInterfaceInit);// TGInterfaceInitFunc;
119 interface_finalize := nil; //TGInterfaceFinalizeFunc;
120 interface_data := nil;//gpointer;
121 end;
122 _LCLLISTVIEW_MODEL_TYPE := g_type_register_static(G_TYPE_OBJECT, ELCLListViewModel, @TypeInfo, 0);
123 g_type_add_interface_static(_LCLLISTVIEW_MODEL_TYPE, GTK_TYPE_TREE_MODEL, @InterfaceInfo);
124 end;
125 Result := _LCLLISTVIEW_MODEL_TYPE;
126 end;
127
128 procedure LCLListViewModelClassInit(g_class:gpointer; class_data:gpointer); cdecl;
129 begin
130 end;
131
132 procedure LCLListViewModelInit(instance:PGTypeInstance; g_class:gpointer); cdecl;
133 begin
134 end;
135
136 procedure LCLListViewModelInterfaceInit(g_iface:PGtkTreeModelIface; iface_data:gpointer); cdecl;
137 var
138 P: PPointer;
139 begin
140 // Do not change the order here!!
141 P := @g_iface^.row_changed;
142
143 P^ := @TLCLListViewModel.row_changed; Inc(P);
144 P^ := @TLCLListViewModel.row_inserted; Inc(P);
145 P^ := @TLCLListViewModel.row_has_child_toggled; Inc(P);
146 P^ := @TLCLListViewModel.row_deleted; Inc(P);
147 P^ := @TLCLListViewModel.rows_reordered; Inc(P);
148 P^ := @TLCLListViewModel.get_flags; Inc(P);
149 P^ := @TLCLListViewModel.get_n_columns; Inc(P);
150 P^ := @TLCLListViewModel.get_column_type; Inc(P);
151 P^ := @TLCLListViewModel.get_iter; Inc(P);
152 P^ := @TLCLListViewModel.get_path; Inc(P);
153 P^ := @TLCLListViewModel.get_value; Inc(P);
154 P^ := @TLCLListViewModel.iter_next; Inc(P);
155 P^ := @TLCLListViewModel.iter_children; Inc(P);
156 P^ := @TLCLListViewModel.iter_has_child; Inc(P);
157 P^ := @TLCLListViewModel.iter_n_children; Inc(P);
158 P^ := @TLCLListViewModel.iter_nth_child; Inc(P);
159 P^ := @TLCLListViewModel.iter_parent; Inc(P);
160 P^ := @TLCLListViewModel.ref_node; Inc(P);
161 P^ := @TLCLListViewModel.unref_node; Inc(P);
162
163 end;
164
165 { TLCLListViewModel }
166
167
168 procedure TLCLListViewModel.row_changed(path: PGtkTreePath; iter: PGtkTreeIter); cdecl;
169 begin
170 end;
171
172 procedure TLCLListViewModel.row_inserted(path: PGtkTreePath; iter: PGtkTreeIter); cdecl;
173 begin
174 end;
175
176 procedure TLCLListViewModel.row_has_child_toggled(path: PGtkTreePath;
177 iter: PGtkTreeIter); cdecl;
178 begin
179 end;
180
181 procedure TLCLListViewModel.row_deleted(path: PGtkTreePath); cdecl;
182 begin
183 end;
184
185 procedure TLCLListViewModel.rows_reordered(path: PGtkTreePath;
186 iter: PGtkTreeIter; new_order: Pgint); cdecl;
187 begin
188 end;
189
get_flagsnull190 function TLCLListViewModel.get_flags(): TGtkTreeModelFlags; cdecl;
191 begin
192 Result := GTK_TREE_MODEL_LIST_ONLY or 0;
193 end;
194
get_n_columnsnull195 function TLCLListViewModel.get_n_columns(): gint; cdecl;
196 begin
197 Result := 1;
198 end;
199
get_column_typenull200 function TLCLListViewModel.get_column_type(index: gint): GType; cdecl;
201 begin
202 Result := G_TYPE_POINTER;
203 end;
204
TLCLListViewModel.get_iternull205 function TLCLListViewModel.get_iter(iter: PGtkTreeIter; path: PGtkTreePath): gboolean; cdecl;
206 var
207 Index: PtrUInt;
208 begin
209 Result := False;
210 Index := gtk_tree_path_get_indices(path)[0];
211 if Index < ListView.Items.Count then
212 begin
213 iter^.user_data:= {%H-}Pointer(Index);
214 Exit(True);
215 end;
216 end;
217
get_pathnull218 function TLCLListViewModel.get_path(iter: PGtkTreeIter): PGtkTreePath; cdecl;
219 var
220 Index: PtrUint;
221 begin
222 Result := nil;
223 if iter = nil then
224 Exit;
225 Index := {%H-}PtrUint(Iter^.user_data);
226 Result := gtk_tree_path_new_from_indices(Index, -1);
227 end;
228
229 procedure TLCLListViewModel.get_value(iter: PGtkTreeIter; column: gint;
230 value: PGValue); cdecl;
231 var
232 Index: Integer;
233 Item: TLVItemHack;
234 //ValueType: GType;
235 //SubIndex: Integer;
236 begin
237 Index := {%H-}PtrUint(Iter^.user_data);
238 Item := TLVItemHack(ListView.Items.Item[Index]);
239
240 g_value_init(value, G_TYPE_POINTER);
241 g_value_set_pointer(value, Pointer(Item));
242
243
244 // We use custom renderers so the below is not needed and was never tested :)
245
246 {
247 Listview Columns in the tree model are stored like so
248 [ 0: Checked. 1: Pixbuf. 2: Caption. 3: Subitem(x) Pixbuf. 4: Subitem(x) Text etc
249 }
250
251 { Case column of
252 0:
253 begin
254 g_value_init(value, G_TYPE_BOOLEAN);
255 g_value_set_boolean(value, Item.GetCheckedInternal);
256 end;
257 1:
258 begin
259 g_value_init(value, GTK_TYPE_PIXMAP);
260 //g_value_set_pointer(ListView.im); !!
261 g_value_set_pointer(value, nil);
262 end;
263 2:
264 begin
265 g_value_init(value, G_TYPE_STRING);
266 g_value_set_static_string(value,PChar(Item.Caption));
267 end;
268 else
269 SubIndex := (column - 3) div 2;
270 if Column and 1 = 0 then // Picbuf
271 begin
272 g_value_init(value, GTK_TYPE_PIXMAP);
273 //g_value_set_pointer(ListView.im); !!
274 g_value_set_pointer(value, nil);
275 end
276 else // Text;
277 begin
278 g_value_init(value, G_TYPE_STRING);
279 if SubIndex >= Item.SubItems.Count then
280 g_value_set_static_string(value,PChar(''))
281 else
282 g_value_set_static_string(value,PChar(Item.SubItems.Strings[SubIndex]));
283 end;
284 end;
285 }
286 end;
287
iter_nextnull288 function TLCLListViewModel.iter_next(iter: PGtkTreeIter): gboolean; cdecl;
289 begin
290 Result := False;
291 if ListView = nil then
292 Exit;
293 Inc({%H-}PtrUInt(Iter^.user_data));
294 Result := {%H-}PtrUint(Iter^.user_data) < ListView.items.Count;
295 end;
296
TLCLListViewModel.iter_childrennull297 function TLCLListViewModel.iter_children(iter: PGtkTreeIter; parent: PGtkTreeIter): gboolean; cdecl;
298 begin
299 Result := False;
300 end;
301
iter_has_childnull302 function TLCLListViewModel.iter_has_child(iter: PGtkTreeIter): gboolean; cdecl;
303 begin
304 Result := false;
305 end;
306
iter_n_childrennull307 function TLCLListViewModel.iter_n_children(iter: PGtkTreeIter): gint; cdecl;
308 begin
309 Result := 0;
310 if (Iter = nil) and (ListView <> nil) then
311 Result := ListView.Items.Count;
312 end;
313
iter_nth_childnull314 function TLCLListViewModel.iter_nth_child(iter: PGtkTreeIter;
315 parent: PGtkTreeIter; n: gint): gboolean; cdecl;
316 begin
317 Result := False;
318 if (ListView = nil) or (parent <> nil) then
319 Exit;
320 if (Iter <> nil) and (n < ListView.Items.Count) then
321 begin
322 {%H-}PtrUint(Iter^.user_data) := n;
323 Result := True;
324 end;
325 end;
326
iter_parentnull327 function TLCLListViewModel.iter_parent(iter: PGtkTreeIter; child: PGtkTreeIter): gboolean; cdecl;
328 begin
329 Result := False;
330 end;
331
332 procedure TLCLListViewModel.ref_node(iter: PGtkTreeIter); cdecl;
333 begin
334
335 end;
336
337 procedure TLCLListViewModel.unref_node(iter: PGtkTreeIter); cdecl;
338 begin
339
340 end;
341
342 procedure TLCLListViewModel.NotifyRowInserted(AIndex: PtrUInt);
343 var
344 Path: PGtkTreePath;
345 Iter: TGtkTreeIter;
346 begin
347 Iter.user_data := {%H-}Pointer(AIndex);
348 path := gtk_tree_path_new_from_indices(AIndex, -1);
349 //emits a signal
350 gtk_tree_model_row_inserted(TreeModel, path, @iter);
351 gtk_tree_path_free(path);
352 end;
353
354 procedure TLCLListViewModel.NotifyRowDeleted(AIndex: PtrUInt);
355 var
356 Path: PGtkTreePath;
357 begin
358 path := gtk_tree_path_new_from_indices(AIndex, -1);
359 //emits a signal
360 gtk_tree_model_row_deleted(TreeModel, path);
361 gtk_tree_path_free(path);
362 end;
363
TLCLListViewModel.TreeModelnull364 function TLCLListViewModel.TreeModel: PGtkTreeModel; inline;
365 begin
366 Result := PGtkTreeModel(@Self);
367 end;
368
369 end.
370