1 #include "e_mod_main.h"
2 
3 /* action selector plugin: provides list of actions registered for
4    candidate types provided by current plugin */
5 
6 typedef struct _Plugin Plugin;
7 
8 struct _Plugin
9 {
10    Evry_Plugin  base;
11    Eina_List   *actions;
12    Eina_Bool    parent;
13    Evry_Action *action;
14 };
15 
16 static Evry_Plugin *_plug = NULL;
17 
18 static void
_finish(Evry_Plugin * plugin)19 _finish(Evry_Plugin *plugin)
20 {
21    GET_PLUGIN(p, plugin);
22 
23    EVRY_PLUGIN_ITEMS_CLEAR(p);
24 
25    eina_list_free(p->actions);
26    E_FREE(p);
27 }
28 
29 static Evry_Plugin *
_browse(Evry_Plugin * plugin,const Evry_Item * it)30 _browse(Evry_Plugin *plugin, const Evry_Item *it)
31 {
32    Evry_Action *act;
33    Plugin *p;
34 
35    if (!(CHECK_TYPE(it, EVRY_TYPE_ACTION)))
36      return NULL;
37 
38    act = EVRY_ACTN(it);
39 
40    EVRY_PLUGIN_INSTANCE(p, plugin);
41    p->actions = act->fetch(act);
42    p->parent = EINA_TRUE;
43    p->action = act;
44 
45    return EVRY_PLUGIN(p);
46 }
47 
48 static Evry_Plugin *
_begin(Evry_Plugin * plugin,const Evry_Item * it)49 _begin(Evry_Plugin *plugin, const Evry_Item *it)
50 {
51    Evry_Action *act;
52    Eina_List *l;
53    Plugin *p;
54 
55    EVRY_PLUGIN_INSTANCE(p, plugin);
56 
57    if (!(CHECK_TYPE(it, EVRY_TYPE_PLUGIN)))
58      {
59         EINA_LIST_FOREACH (evry_conf->actions, l, act)
60           {
61              if (!((!act->it1.type) ||
62                    (CHECK_TYPE(it, act->it1.type)) ||
63                    (CHECK_SUBTYPE(it, act->it1.type))))
64                continue;
65 
66              if (act->check_item && !(act->check_item(act, it)))
67                continue;
68 
69              act->base.plugin = EVRY_PLUGIN(p);
70              act->it1.item = it;
71              EVRY_ITEM(act)->hi = NULL;
72 
73              p->actions = eina_list_append(p->actions, act);
74           }
75      }
76 
77    if (it->plugin)
78      {
79         EINA_LIST_FOREACH (it->plugin->actions, l, act)
80           {
81              act->base.plugin = EVRY_PLUGIN(p);
82 
83              act->it1.item = EVRY_ITEM(it->plugin);
84              EVRY_ITEM(act)->hi = NULL;
85              p->actions = eina_list_append(p->actions, act);
86           }
87      }
88 
89    return EVRY_PLUGIN(p);
90 }
91 
92 static int
_cb_sort(const void * data1,const void * data2)93 _cb_sort(const void *data1, const void *data2)
94 {
95    const Evry_Item *it1 = data1;
96    const Evry_Item *it2 = data2;
97    const Evry_Action *act1 = data1;
98    const Evry_Action *act2 = data2;
99 
100    if (act1->remember_context || act2->remember_context)
101      {
102         if (act1->remember_context && !act2->remember_context)
103           return -1;
104         if (!act1->remember_context && act2->remember_context)
105           return 1;
106      }
107 
108    /* sort type match before subtype match */
109    if (act1->it1.item && act2->it1.item)
110      {
111         if ((act1->it1.type == act1->it1.item->type) &&
112             (act2->it1.type != act2->it1.item->type))
113           return -1;
114 
115         if ((act1->it1.type != act1->it1.item->type) &&
116             (act2->it1.type == act2->it1.item->type))
117           return 1;
118      }
119 
120    if (it1->fuzzy_match || it2->fuzzy_match)
121      if (it1->fuzzy_match || it2->fuzzy_match)
122        {
123           if (it1->fuzzy_match && !it2->fuzzy_match)
124             return -1;
125 
126           if (!it1->fuzzy_match && it2->fuzzy_match)
127             return 1;
128 
129           if (it1->fuzzy_match - it2->fuzzy_match)
130             return it1->fuzzy_match - it2->fuzzy_match;
131        }
132 
133    if (it1->priority - it2->priority)
134      return it1->priority - it2->priority;
135 
136    return 0;
137 }
138 
139 static int
_fetch(Evry_Plugin * plugin,const char * input)140 _fetch(Evry_Plugin *plugin, const char *input)
141 {
142    GET_PLUGIN(p, plugin);
143    Eina_List *l;
144    Evry_Item *it;
145    int match;
146 
147    EVRY_PLUGIN_ITEMS_CLEAR(p);
148 
149    EINA_LIST_FOREACH (p->actions, l, it)
150      {
151         match = evry_fuzzy_match(it->label, input);
152 
153         if (!input || match)
154           {
155              it->fuzzy_match = match;
156              EVRY_PLUGIN_ITEM_APPEND(p, it);
157           }
158      }
159 
160    if (!plugin->items) return 0;
161 
162    EVRY_PLUGIN_ITEMS_SORT(p, _cb_sort);
163 
164    return 1;
165 }
166 
167 /***************************************************************************/
168 
169 int
evry_plug_actions_init()170 evry_plug_actions_init()
171 {
172    _plug = EVRY_PLUGIN_BASE(N_("Actions"), NULL, EVRY_TYPE_ACTION,
173                             _begin, _finish, _fetch);
174 
175    _plug->browse = &_browse;
176 
177    evry_plugin_register(_plug, EVRY_PLUGIN_ACTION, 2);
178 
179    return 1;
180 }
181 
182 void
evry_plug_actions_shutdown()183 evry_plug_actions_shutdown()
184 {
185    Evry_Item *it;
186 
187    evry_plugin_free(_plug);
188 
189    /* bypass unregister, because it modifies the list */
190    EINA_LIST_FREE (evry_conf->actions, it)
191      evry_item_free(it);
192 }
193 
194 void
evry_action_register(Evry_Action * act,int priority)195 evry_action_register(Evry_Action *act, int priority)
196 {
197    EVRY_ITEM(act)->priority = priority;
198 
199    evry_conf->actions = eina_list_append(evry_conf->actions, act);
200    /* TODO sorting, initialization, etc */
201 }
202 
203 void
evry_action_unregister(Evry_Action * act)204 evry_action_unregister(Evry_Action *act)
205 {
206    evry_conf->actions = eina_list_remove(evry_conf->actions, act);
207    /* finish */
208 }
209 
210 static void
_action_free_cb(Evry_Item * it)211 _action_free_cb(Evry_Item *it)
212 {
213    GET_ACTION(act, it);
214 
215    IF_RELEASE(act->name);
216 
217    E_FREE(act);
218 }
219 
220 Evry_Action *
evry_action_new(const char * name,const char * label,Evry_Type type_in1,Evry_Type type_in2,const char * icon,int (* action)(Evry_Action * act),int (* check_item)(Evry_Action * act,const Evry_Item * it))221 evry_action_new(const char *name, const char *label,
222                 Evry_Type type_in1, Evry_Type type_in2,
223                 const char *icon,
224                 int (*action)(Evry_Action *act),
225                 int (*check_item)(Evry_Action *act, const Evry_Item *it))
226 {
227    Evry_Action *act = EVRY_ITEM_NEW(Evry_Action, _plug, label,
228                                     NULL, _action_free_cb);
229    if (icon)
230      act->base.icon = eina_stringshare_add(icon);
231 
232    act->name = eina_stringshare_add(name);
233 
234    act->it1.type = type_in1;
235    act->it2.type = type_in2;
236 
237    act->action = action;
238    act->check_item = check_item;
239 
240    return act;
241 }
242 
243 void
evry_action_free(Evry_Action * act)244 evry_action_free(Evry_Action *act)
245 {
246    evry_action_unregister(act);
247 
248    evry_item_free(EVRY_ITEM(act));
249 }
250 
251 /* TODO assign actions to plugins othersie there will be too liitle
252    names soon */
253 Evry_Action *
evry_action_find(const char * name)254 evry_action_find(const char *name)
255 {
256    Evry_Action *act = NULL;
257    Eina_List *l;
258 
259    const char *n = eina_stringshare_add(name);
260 
261    EINA_LIST_FOREACH (evry_conf->actions, l, act)
262      if (act->name == n)
263        break;
264 
265    eina_stringshare_del(n);
266 
267    return act;
268 }
269 
270