static void _add_remove_recursive (MexModel *queue_model, MexModel *model, gboolean add) { gint len, i; len = mex_model_get_length (model); for (i=0; i < len; i++) { MexContent *content; const gchar *mimetype; content = mex_model_get_content (model, i); mimetype = mex_content_get_metadata (content, MEX_CONTENT_METADATA_MIMETYPE); /* Don't accidentally add a directory or group to the queue */ if (!g_strcmp0 (mimetype, "x-grl/box") || !g_strcmp0 (mimetype, "x-mex/group")) continue; if (add) mex_model_add_content (queue_model, content); else mex_model_remove_content (queue_model, content); } g_object_unref (model); }
static void or_add_to_feed (gpointer key, gpointer value, gpointer userdata) { MexModel *model = (MexModel *) userdata; /* The key and value are the same, doesn't matter which we add */ mex_model_add_content (model, (MexContent *) key); }
/* This function is synchronous! Blocking once at startup seems pretty * reasonable and allows us to avoid any complexity re. races */ static void mex_queue_model_load (MexQueueModel *model) { JsonParser *parser; gchar *filename; GError *error = NULL; JsonNode *root; JsonArray *array; gint i = 0; filename = _queue_file_name (); if (!g_file_test (filename, G_FILE_TEST_EXISTS)) { g_free (filename); return; } parser = json_parser_new (); if (!json_parser_load_from_file (parser, filename, &error)) { g_warning (G_STRLOC ": error populating from file: %s", error->message); g_clear_error (&error); goto out; } root = json_parser_get_root (parser); if (!JSON_NODE_HOLDS_ARRAY (root)) { g_warning (G_STRLOC ": JSON data not of expected format!"); goto out; } array = json_node_get_array (root); for (i = 0; i < json_array_get_length (array); i++) { MexContent *content; JsonNode *node; node = json_array_get_element (array, i); content = (MexContent *)json_gobject_deserialize (MEX_TYPE_PROGRAM, node); mex_model_add_content (MEX_MODEL (model), content); } out: g_free (filename); g_object_unref (parser); }
static void and_add_to_feed (gpointer key, gpointer value, gpointer userdata) { struct _SearchPayload *payload = (struct _SearchPayload *) userdata; /* @value is the number of terms that the program in @key was found related to. For AND operations the program needs to have been found related to all of the terms */ if (GPOINTER_TO_INT (value) == payload->term_count) { mex_model_add_content (payload->model, (MexContent *) key); } }
void mex_aggregate_model_add_model (MexAggregateModel *aggregate, MexModel *model) { gint i; MexContent *content; GController *controller; MexAggregateModelPrivate *priv; g_return_if_fail (MEX_IS_AGGREGATE_MODEL (aggregate)); g_return_if_fail (MEX_IS_MODEL (model)); priv = aggregate->priv; if (g_list_find (priv->models, model)) return; /* Add a link back to the model from the controller */ controller = mex_model_get_controller (model); g_hash_table_insert (priv->controller_to_model, controller, model); /* Add model to list */ priv->models = g_list_insert_sorted (priv->models, model, (GCompareFunc) mex_aggregate_model_sort_func); /* Add existing items */ i = 0; while ((content = mex_model_get_content (model, i))) { g_hash_table_insert (priv->content_to_model, content, model); mex_model_add_content (MEX_MODEL (aggregate), content); i++; } /* Connect to the controller changed signal */ g_signal_connect (controller, "changed", G_CALLBACK (mex_aggregate_model_controller_changed_cb), aggregate); /* Emit added signal */ g_signal_emit (aggregate, signals[MODEL_ADDED], 0, model); }
static void _queue_button_notify_toggled_cb (MxButton *button, GParamSpec *pspec, MexQueueButton *q_button) { MexQueueButtonPrivate *priv = q_button->priv; const gchar *mimetype; gboolean directory; mimetype = mex_content_get_metadata (priv->content, MEX_CONTENT_METADATA_MIMETYPE); directory = !g_strcmp0 (mimetype, "x-grl/box") || !g_strcmp0 (mimetype, "x-mex/group"); /* Triggers a train of actions that makes content have it's queued * property set which then runs the notify cb which calls * mex_queue_button_update so we don't need to run it directly */ if (mx_button_get_toggled (button)) { mex_queue_button_set_animated (q_button, TRUE); if (directory) _add_from_directory (q_button, TRUE); else mex_model_add_content (priv->queue_model, priv->content); } else { mex_queue_button_set_animated (q_button, FALSE); if (directory) _add_from_directory (q_button, FALSE); else mex_model_remove_content (priv->queue_model, priv->content); } }
static void mex_aggregate_model_controller_changed_cb (GController *controller, GControllerAction action, GControllerReference *ref, MexAggregateModel *self) { gint i; gint n_indices = 0; MexAggregateModelPrivate *priv = self->priv; MexModel *model = g_hash_table_lookup (priv->controller_to_model, controller); if (!model) { g_warning (G_STRLOC ": Signal from unknown controller"); return; } if (ref) n_indices = g_controller_reference_get_n_indices (ref); switch (action) { case G_CONTROLLER_ADD: for (i = 0; i < n_indices; i++) { MexContent *content; gint content_index = g_controller_reference_get_index_uint (ref, i); content = mex_model_get_content (model, content_index); g_hash_table_insert (priv->content_to_model, content, model); mex_model_add_content (MEX_MODEL (self), content); } break; case G_CONTROLLER_REMOVE: for (i = 0; i < n_indices; i++) { MexContent *content; gint content_index = g_controller_reference_get_index_uint (ref, i); content = mex_model_get_content (model, content_index); g_hash_table_remove (priv->content_to_model, content); mex_model_remove_content (MEX_MODEL (self), content); } break; case G_CONTROLLER_UPDATE: break; case G_CONTROLLER_CLEAR: mex_aggregate_model_clear_model (self, model); break; case G_CONTROLLER_REPLACE: { MexContent *content; mex_aggregate_model_clear_model (self, model); i = 0; while ((content = mex_model_get_content (model, i++))) { g_hash_table_insert (priv->content_to_model, content, model); mex_model_add_content (MEX_MODEL (self), content); } } break; case G_CONTROLLER_INVALID_ACTION: g_warning (G_STRLOC ": Proxy controller has issued an error"); break; default: break; } }
static void mex_suggest_complete_cb (MexDownloadQueue *queue, const gchar *uri, const gchar *buffer, gsize count, const GError *error, gpointer userdata) { RestXmlNode *root, *n; RestXmlParser *parser; MexSearchPlugin *self = userdata; MexSearchPluginPrivate *priv = self->priv; priv->suggest_id = NULL; /* hide spinner */ mx_spinner_set_animating (MX_SPINNER (priv->spinner), FALSE); clutter_actor_hide (priv->spinner); if (error) { g_warning ("Error querying Google suggestions: %s", error->message); return; } parser = rest_xml_parser_new (); root = rest_xml_parser_parse_from_data (parser, buffer, count); if (!root) { g_warning ("Unknown error parsing Google suggestions XML"); g_object_unref (parser); return; } /* Clear model */ mex_model_clear (MEX_MODEL (priv->suggest_model)); /* Add new suggestions to model */ n = rest_xml_node_find (root, "CompleteSuggestion"); for (; n; n = n->next) { MexContent *content; const gchar *suggestion; RestXmlNode *node = rest_xml_node_find (n, "suggestion"); if (!node) continue; suggestion = rest_xml_node_get_attr (node, "data"); if (!suggestion) continue; content = MEX_CONTENT (mex_program_new (priv->suggest_model)); mex_content_set_metadata (content, MEX_CONTENT_METADATA_TITLE, suggestion); mex_content_set_metadata (content, MEX_CONTENT_METADATA_MIMETYPE, "x-mex/search"); mex_model_add_content (MEX_MODEL (priv->suggest_model), content); } /* Unref */ rest_xml_node_unref (root); g_object_unref (parser); }
static void mex_search_plugin_update_history (MexSearchPlugin *self, const gchar *term) { gint i; gsize length; gchar *contents, *current; MexSearchPluginPrivate *priv = self->priv; const gchar *base_dir = mex_settings_get_config_dir (mex_settings_get_default ()); gchar *history_file = g_build_filename (base_dir, "search", "history", NULL); /* Read the history file contents */ /* TODO: Make this less rubbish? */ g_file_get_contents (history_file, &contents, &length, NULL); /* Prepend new search-term if appropriate */ if (term) { gint terms; gchar *path; gsize new_length; gsize term_len = strlen (term); gchar *new_contents = g_malloc (length + term_len + 1); memcpy (new_contents, term, term_len); new_contents[term_len] = '\n'; new_length = term_len + 1; /* Truncate list to 10 terms and remove duplicates */ if (contents) { i = 0; terms = 1; do { gint cur_len; char *eos = strchr (contents + i, '\n'); if (!eos) cur_len = strlen (contents + i); else cur_len = eos - (contents + i); if ((cur_len != term_len) || (strncmp (contents + i, term, term_len) != 0)) { memcpy (new_contents + new_length, contents + i, cur_len + 1); new_length += cur_len + 1; if (++terms >= 10) break; } if (!eos) break; i += cur_len + 1; } while (i < length); } new_contents[new_length++] = '\0'; /* Save new list */ path = g_path_get_dirname (history_file); g_mkdir_with_parents (path, 0755); g_free (path); g_file_set_contents (history_file, new_contents, new_length, NULL); /* Replace content with new content */ g_free (contents); contents = new_contents; length = new_length; } /* Empty current list */ mex_model_clear (MEX_MODEL (priv->history_model)); /* Populate with search history */ if (contents) { current = contents; while (current < contents + length) { MexContent *content = MEX_CONTENT (mex_program_new (priv->history_model)); gchar *end = g_utf8_strchr (current, -1, '\n'); if (end) *end = '\0'; if (*current) { mex_content_set_metadata (content, MEX_CONTENT_METADATA_TITLE, current); mex_content_set_metadata (content, MEX_CONTENT_METADATA_MIMETYPE, "x-mex/search"); mex_model_add_content (MEX_MODEL (priv->history_model), content); } if (end) current = end + 1; else break; } g_free (contents); } else { /* Add a default search so the column isn't hidden. * TODO: Have a way of inserting 'stock' content rather than doing * this, I suppose. */ MexContent *content = MEX_CONTENT (mex_program_new (priv->history_model)); mex_content_set_metadata (content, MEX_CONTENT_METADATA_TITLE, "MeeGo"); mex_content_set_metadata (content, MEX_CONTENT_METADATA_MIMETYPE, "x-mex/search"); mex_model_add_content (MEX_MODEL (priv->history_model), content); } }