1 /*
2    This file is part of darktable,
3    Copyright (C) 2013-2021 darktable developers.
4 
5    darktable is free software: you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation, either version 3 of the License, or
8    (at your option) any later version.
9 
10    darktable is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14 
15    You should have received a copy of the GNU General Public License
16    along with darktable.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 #include "lua/tags.h"
19 #include "common/darktable.h"
20 #include "common/debug.h"
21 #include "common/image.h"
22 #include "common/tags.h"
23 #include "control/signal.h"
24 #include "lua/image.h"
25 #include "lua/types.h"
26 
27 
tag_name(lua_State * L)28 static int tag_name(lua_State *L)
29 {
30   dt_lua_tag_t tagid1;
31   luaA_to(L, dt_lua_tag_t, &tagid1, -2);
32   gchar *name = dt_tag_get_name(tagid1);
33   lua_pushstring(L, name);
34   free(name);
35   return 1;
36 }
37 
tag_tostring(lua_State * L)38 static int tag_tostring(lua_State *L)
39 {
40   dt_lua_tag_t tagid1;
41   luaA_to(L, dt_lua_tag_t, &tagid1, -1);
42   gchar *name = dt_tag_get_name(tagid1);
43   lua_pushstring(L, name);
44   free(name);
45   return 1;
46 }
47 
tag_length(lua_State * L)48 static int tag_length(lua_State *L)
49 {
50   dt_lua_tag_t tagid;
51   luaA_to(L, dt_lua_tag_t, &tagid, -1);
52   sqlite3_stmt *stmt;
53   int rv, count = -1;
54 
55   DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db),
56                               "SELECT COUNT(*) FROM main.tagged_images WHERE tagid=?1", -1, &stmt, NULL);
57   DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, tagid);
58   rv = sqlite3_step(stmt);
59   if(rv != SQLITE_ROW)
60   {
61     sqlite3_finalize(stmt);
62     return luaL_error(L, "unknown SQL error");
63   }
64   count = sqlite3_column_int(stmt, 0);
65   lua_pushinteger(L, count);
66   sqlite3_finalize(stmt);
67   return 1;
68 }
tag_index(lua_State * L)69 static int tag_index(lua_State *L)
70 {
71   dt_lua_tag_t tagid;
72   luaA_to(L, dt_lua_tag_t, &tagid, -2);
73   int index = luaL_checkinteger(L, -1);
74   if(index < 1)
75   {
76     return luaL_error(L, "incorrect index in database");
77   }
78   sqlite3_stmt *stmt = NULL;
79   char query[1024];
80   snprintf(query, sizeof(query),
81            "SELECT imgid FROM main.tagged_images WHERE tagid=?1 ORDER BY imgid LIMIT 1 OFFSET %d", index - 1);
82   DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), query, -1, &stmt, NULL);
83   DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, tagid);
84   if(sqlite3_step(stmt) == SQLITE_ROW)
85   {
86     int imgid = sqlite3_column_int(stmt, 0);
87     luaA_push(L, dt_lua_image_t, &imgid);
88   }
89   else
90   {
91     sqlite3_finalize(stmt);
92     luaL_error(L, "incorrect index in database");
93   }
94   sqlite3_finalize(stmt);
95   return 1;
96 }
97 
98 
tag_lib_length(lua_State * L)99 static int tag_lib_length(lua_State *L)
100 {
101   sqlite3_stmt *stmt;
102   int rv, count = -1;
103 
104   DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "SELECT COUNT(*) FROM data.tags", -1, &stmt, NULL);
105   rv = sqlite3_step(stmt);
106   if(rv != SQLITE_ROW)
107   {
108     sqlite3_finalize(stmt);
109     return luaL_error(L, "unknown SQL error");
110   }
111   count = sqlite3_column_int(stmt, 0);
112   lua_pushinteger(L, count);
113   sqlite3_finalize(stmt);
114   return 1;
115 }
tag_lib_index(lua_State * L)116 static int tag_lib_index(lua_State *L)
117 {
118   int index = luaL_checkinteger(L, -1);
119   sqlite3_stmt *stmt = NULL;
120   char query[1024];
121   snprintf(query, sizeof(query), "SELECT id FROM data.tags ORDER BY id LIMIT 1 OFFSET %d", index - 1);
122   DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), query, -1, &stmt, NULL);
123   if(sqlite3_step(stmt) == SQLITE_ROW)
124   {
125     int tagid = sqlite3_column_int(stmt, 0);
126     luaA_push(L, dt_lua_tag_t, &tagid);
127   }
128   else
129   {
130     lua_pushnil(L);
131   }
132   sqlite3_finalize(stmt);
133   return 1;
134 }
135 
tag_lib_create(lua_State * L)136 static int tag_lib_create(lua_State *L)
137 {
138   const char *name = luaL_checkstring(L, 1);
139   dt_lua_tag_t tagid;
140   if(!dt_tag_new_from_gui(name, &tagid))
141   {
142     return luaL_error(L, "error creating tag %s\n", name);
143   }
144   luaA_push(L, dt_lua_tag_t, &tagid);
145   return 1;
146 }
147 
tag_delete(lua_State * L)148 static int tag_delete(lua_State *L)
149 {
150   dt_lua_tag_t tagid;
151   luaA_to(L, dt_lua_tag_t, &tagid, -1);
152 
153   GList *tagged_images = NULL;
154   sqlite3_stmt *stmt;
155   DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "SELECT imgid FROM main.tagged_images WHERE tagid=?1",
156                               -1, &stmt, NULL);
157   DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, tagid);
158   while(sqlite3_step(stmt) == SQLITE_ROW)
159   {
160     tagged_images = g_list_append(tagged_images, GINT_TO_POINTER(sqlite3_column_int(stmt, 0)));
161   }
162   sqlite3_finalize(stmt);
163 
164   if(dt_tag_remove(tagid, TRUE))
165     DT_DEBUG_CONTROL_SIGNAL_RAISE(darktable.signals, DT_SIGNAL_TAG_CHANGED);
166 
167   for(const GList *list_iter = tagged_images; list_iter; list_iter = g_list_next(list_iter))
168   {
169     dt_image_synch_xmp(GPOINTER_TO_INT(list_iter->data));
170   }
171   g_list_free(tagged_images);
172 
173   return 0;
174 }
175 
176 
dt_lua_tag_attach(lua_State * L)177 int dt_lua_tag_attach(lua_State *L)
178 {
179   dt_lua_image_t imgid = -1;
180   dt_lua_tag_t tagid = 0;
181   if(luaL_testudata(L, 1, "dt_lua_image_t"))
182   {
183     luaA_to(L, dt_lua_image_t, &imgid, 1);
184     luaA_to(L, dt_lua_tag_t, &tagid, 2);
185   }
186   else
187   {
188     luaA_to(L, dt_lua_tag_t, &tagid, 1);
189     luaA_to(L, dt_lua_image_t, &imgid, 2);
190   }
191   if(dt_tag_attach(tagid, imgid, TRUE, TRUE))
192   {
193     DT_DEBUG_CONTROL_SIGNAL_RAISE(darktable.signals, DT_SIGNAL_TAG_CHANGED);
194     dt_image_synch_xmp(imgid);
195   }
196   return 0;
197 }
198 
dt_lua_tag_detach(lua_State * L)199 int dt_lua_tag_detach(lua_State *L)
200 {
201   dt_lua_image_t imgid;
202   dt_lua_tag_t tagid;
203   if(luaL_testudata(L, 1, "dt_lua_image_t"))
204   {
205     luaA_to(L, dt_lua_image_t, &imgid, 1);
206     luaA_to(L, dt_lua_tag_t, &tagid, 2);
207   }
208   else
209   {
210     luaA_to(L, dt_lua_tag_t, &tagid, 1);
211     luaA_to(L, dt_lua_image_t, &imgid, 2);
212   }
213   if(dt_tag_detach(tagid, imgid, TRUE, TRUE))
214   {
215     dt_image_synch_xmp(imgid);
216     DT_DEBUG_CONTROL_SIGNAL_RAISE(darktable.signals, DT_SIGNAL_TAG_CHANGED);
217   }
218   return 0;
219 }
220 
tag_lib_find(lua_State * L)221 static int tag_lib_find(lua_State *L)
222 {
223   const char *name = luaL_checkstring(L, 1);
224   dt_lua_tag_t tagid;
225   if(!dt_tag_exists(name, &tagid))
226   {
227     lua_pushnil(L);
228     return 1;
229   }
230   luaA_push(L, dt_lua_tag_t, &tagid);
231   return 1;
232 }
233 
dt_lua_tag_get_attached(lua_State * L)234 int dt_lua_tag_get_attached(lua_State *L)
235 {
236   dt_lua_image_t imgid;
237   int table_index = 1;
238   luaA_to(L, dt_lua_image_t, &imgid, 1);
239   sqlite3_stmt *stmt;
240 
241   DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "SELECT tagid FROM main.tagged_images WHERE imgid=?1",
242                               -1, &stmt, NULL);
243   DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, imgid);
244   int rv = sqlite3_step(stmt);
245   lua_newtable(L);
246   while(rv == SQLITE_ROW)
247   {
248     int tagid = sqlite3_column_int(stmt, 0);
249     luaA_push(L, dt_lua_tag_t, &tagid);
250     lua_seti(L, -2, table_index);
251     table_index++;
252     rv = sqlite3_step(stmt);
253   }
254   sqlite3_finalize(stmt);
255   return 1;
256 }
257 
258 
dt_lua_tag_get_tagged_images(lua_State * L)259 int dt_lua_tag_get_tagged_images(lua_State *L)
260 {
261   dt_lua_tag_t tagid;
262   int table_index = 1;
263   luaA_to(L, dt_lua_tag_t, &tagid, 1);
264   sqlite3_stmt *stmt;
265 
266   DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "SELECT imgid FROM main.tagged_images WHERE tagid=?1",
267                               -1, &stmt, NULL);
268   DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, tagid);
269   int rv = sqlite3_step(stmt);
270   lua_newtable(L);
271   while(rv == SQLITE_ROW)
272   {
273     int imgid = sqlite3_column_int(stmt, 0);
274     luaA_push(L, dt_lua_image_t, &imgid);
275     lua_seti(L, -2, table_index);
276     table_index++;
277     rv = sqlite3_step(stmt);
278   }
279   sqlite3_finalize(stmt);
280   return 1;
281 }
282 
283 
dt_lua_init_tags(lua_State * L)284 int dt_lua_init_tags(lua_State *L)
285 {
286   dt_lua_init_int_type(L, dt_lua_tag_t);
287   lua_pushcfunction(L, tag_length);
288   lua_pushcfunction(L, tag_index);
289   dt_lua_type_register_number_const(L, dt_lua_tag_t);
290   lua_pushcfunction(L, tag_name);
291   dt_lua_type_register_const(L, dt_lua_tag_t, "name");
292   lua_pushcfunction(L, tag_delete);
293   lua_pushcclosure(L, dt_lua_type_member_common, 1);
294   dt_lua_type_register_const(L, dt_lua_tag_t, "delete");
295   lua_pushcfunction(L, dt_lua_tag_attach);
296   lua_pushcclosure(L, dt_lua_type_member_common, 1);
297   dt_lua_type_register_const(L, dt_lua_tag_t, "attach");
298   lua_pushcfunction(L, dt_lua_tag_detach);
299   lua_pushcclosure(L, dt_lua_type_member_common, 1);
300   dt_lua_type_register_const(L, dt_lua_tag_t, "detach");
301   lua_pushcfunction(L, tag_tostring);
302   dt_lua_type_setmetafield(L, dt_lua_tag_t, "__tostring");
303 
304   /* tags */
305   dt_lua_push_darktable_lib(L);
306   luaA_Type type_id = dt_lua_init_singleton(L, "tag_table", NULL);
307   lua_setfield(L, -2, "tags");
308   lua_pop(L, 1);
309 
310   lua_pushcfunction(L, tag_lib_length);
311   lua_pushcfunction(L, tag_lib_index);
312   dt_lua_type_register_number_const_type(L, type_id);
313   lua_pushcfunction(L, tag_lib_create);
314   lua_pushcclosure(L, dt_lua_type_member_common, 1);
315   dt_lua_type_register_const_type(L, type_id, "create");
316   lua_pushcfunction(L, tag_lib_find);
317   lua_pushcclosure(L, dt_lua_type_member_common, 1);
318   dt_lua_type_register_const_type(L, type_id, "find");
319   lua_pushcfunction(L, tag_delete);
320   lua_pushcclosure(L, dt_lua_type_member_common, 1);
321   dt_lua_type_register_const_type(L, type_id, "delete");
322   lua_pushcfunction(L, dt_lua_tag_attach);
323   lua_pushcclosure(L, dt_lua_type_member_common, 1);
324   dt_lua_type_register_const_type(L, type_id, "attach");
325   lua_pushcfunction(L, dt_lua_tag_detach);
326   lua_pushcclosure(L, dt_lua_type_member_common, 1);
327   dt_lua_type_register_const_type(L, type_id, "detach");
328   lua_pushcfunction(L, dt_lua_tag_get_attached);
329   lua_pushcclosure(L, dt_lua_type_member_common, 1);
330   dt_lua_type_register_const_type(L, type_id, "get_tags");
331   lua_pushcfunction(L, dt_lua_tag_get_tagged_images);
332   lua_pushcclosure(L, dt_lua_type_member_common, 1);
333   dt_lua_type_register_const_type(L, type_id, "get_tagged_images");
334 
335 
336   return 0;
337 }
338 // modelines: These editor modelines have been set for all relevant files by tools/update_modelines.sh
339 // vim: shiftwidth=2 expandtab tabstop=2 cindent
340 // kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
341