enventor/src/bin/search.c

392 lines
11 KiB
C

#include <Elementary.h>
#include "common.h"
typedef struct search_s
{
Evas_Object *win;
Evas_Object *layout;
Evas_Object *en_find;
Evas_Object *en_replace;
Evas_Object *entry;
int pos;
Eina_Bool forward : 1;
} search_data;
static search_data *g_sd = NULL;
static Evas_Object *g_entry = NULL;
static Evas_Coord win_x = -1;
static Evas_Coord win_y = -1;
static Evas_Coord win_w = DEFAULT_SEARCH_WIN_W;
static Evas_Coord win_h = DEFAULT_SEARCH_WIN_H;
static void
win_delete_request_cb(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED,
void *event_info EINA_UNUSED)
{
search_close();
}
static void
win_moved_cb(void *data EINA_UNUSED, Evas_Object *obj,
void *event_info EINA_UNUSED)
{
/* Move the window with the previous remembered position when the window is
moved by window manager first time. */
if ((win_x != -1) || (win_y != -1)) evas_object_move(obj, win_x, win_y);
evas_object_smart_callback_del(obj, "moved", win_moved_cb);
}
static void
replace_all_proc(search_data *sd)
{
const char *find = elm_entry_entry_get(sd->en_find);
if (!find) return;
int find_len = strlen(find);
const char *replace = elm_entry_entry_get(sd->en_replace);
int replace_len = 0;
//Same word. no need to replace
if (replace)
{
replace_len = strlen(replace);
if (!strcmp(find, replace) && (find_len == replace_len))
return;
}
char buf[256];
int replace_cnt = 0;
const char *text = elm_entry_entry_get(sd->entry);
char *utf8 = elm_entry_markup_to_utf8(text);
char *s = utf8;
int pos;
int delta = replace_len - find_len;
while ((s = strstr(s, find)))
{
pos = s + (delta * replace_cnt) - utf8;
elm_entry_select_region_set(sd->entry, pos, pos + find_len);
elm_entry_entry_insert(sd->entry, replace);
elm_entry_select_none(sd->entry);
replace_cnt++;
s++;
}
snprintf(buf, sizeof(buf), "%d matches replaced", replace_cnt);
stats_info_msg_update(buf);
free(utf8);
}
static void
find_forward_proc(search_data *sd)
{
const char *find = elm_entry_entry_get(sd->en_find);
if (!find) return;
char buf[256];
Eina_Bool need_iterate = EINA_TRUE;
const char *text = elm_entry_entry_get(sd->entry);
if (!text) return;
char *utf8 = elm_entry_markup_to_utf8(text);
//get the character position begun with searching.
if (sd->pos == -1) sd->pos = elm_entry_cursor_pos_get(sd->entry);
else if (sd->pos == 0) need_iterate = EINA_FALSE;
else sd->pos++;
char *s = strstr((utf8 + sd->pos), find);
//No found
if (!s)
{
//Need to iterate finding?
if (need_iterate)
{
sd->pos = 0;
find_forward_proc(sd);
}
//There are no searched words in the text
else
{
snprintf(buf, sizeof(buf), "No \"%s\" in the text", find);
stats_info_msg_update(buf);
sd->pos = -1;
}
free(utf8);
return;
}
//Got you!
int len = strlen(find);
sd->pos = s - utf8;
elm_entry_select_none(sd->entry);
elm_entry_select_region_set(sd->entry, sd->pos, sd->pos + len);
free(utf8);
}
static void
find_backward_proc(search_data *sd)
{
const char *find = elm_entry_entry_get(sd->en_find);
if (!find) return;
char buf[256];
Eina_Bool need_iterate = EINA_TRUE;
int len;
const char *text = elm_entry_entry_get(sd->entry);
if (!text) return;
char *utf8 = elm_entry_markup_to_utf8(text);
//get the character position begun with searching.
if (sd->pos == -1)
{
sd->pos = elm_entry_cursor_pos_get(sd->entry);
}
else
{
len = strlen(utf8);
if (sd->pos == len) need_iterate = EINA_FALSE;
}
char *prev = NULL;
char *s = utf8;
while (s = strstr(s, find))
{
if ((s - utf8) >= sd->pos) break;
prev = s;
s++;
}
//No found. Need to iterate finding?
if (!prev)
{
if (need_iterate)
{
sd->pos = len;
find_backward_proc(sd);
}
else
{
snprintf(buf, sizeof(buf), "No \"%s\" in the text", find);
stats_info_msg_update(buf);
sd->pos = -1;
}
free(utf8);
return;
}
//Got you!
sd->pos = prev - utf8;
elm_entry_select_none(sd->entry);
elm_entry_select_region_set(sd->entry, sd->pos, sd->pos + strlen(find));
free(utf8);
}
static Eina_Bool
replace_proc(search_data *sd)
{
const char *find = elm_entry_entry_get(sd->en_find);
const char *selection = elm_entry_selection_get(sd->entry);
if (!find || !selection) return EINA_FALSE;
char *utf8 = elm_entry_markup_to_utf8(selection);
if (strcmp(find, utf8)) return EINA_FALSE;
const char *replace = elm_entry_entry_get(sd->en_replace);
elm_entry_entry_insert(sd->entry, replace);
free(utf8);
return EINA_TRUE;
}
static void
backward_clicked_cb(void *data, Evas_Object *obj EINA_UNUSED,
void *event_info EINA_UNUSED)
{
search_data *sd = data;
find_backward_proc(sd);
sd->forward = EINA_FALSE;
elm_object_part_text_set(sd->layout, "elm.text.dir", "Backward");
}
static void
replace_clicked_cb(void *data, Evas_Object *obj EINA_UNUSED,
void *event_info EINA_UNUSED)
{
search_data *sd = data;
Eina_Bool next;
next = replace_proc(sd);
if (!next) return;
if (sd->forward) find_forward_proc(sd);
else find_backward_proc(sd);
}
static void
replace_all_clicked_cb(void *data, Evas_Object *obj EINA_UNUSED,
void *event_info EINA_UNUSED)
{
search_data *sd = data;
replace_all_proc(sd);
}
static void
forward_clicked_cb(void *data, Evas_Object *obj EINA_UNUSED,
void *event_info EINA_UNUSED)
{
search_data *sd = data;
find_forward_proc(sd);
sd->forward = EINA_TRUE;
elm_object_part_text_set(sd->layout, "elm.text.dir", "Forward");
}
static void
find_activated_cb(void *data, Evas_Object *obj EINA_UNUSED,
void* event_info EINA_UNUSED)
{
search_data *sd = data;
if (sd->forward) find_forward_proc(sd);
else find_backward_proc(sd);
}
static void
replace_activated_cb(void *data, Evas_Object *obj EINA_UNUSED,
void* event_info EINA_UNUSED)
{
search_data *sd = data;
Eina_Bool next;
next = replace_proc(sd);
if (!next) return;
if (sd->forward) find_forward_proc(sd);
else find_backward_proc(sd);
}
void
search_open()
{
search_data *sd = g_sd;
if (sd)
{
elm_win_activate(sd->win);
return;
}
goto_close();
sd = calloc(1, sizeof(search_data));
g_sd = sd;
//Win
Evas_Object *win = elm_win_add(base_win_get(), "Enventor Search",
ELM_WIN_DIALOG_BASIC);
elm_win_focus_highlight_enabled_set(win, EINA_TRUE);
elm_win_title_set(win, "Find/Replace");
evas_object_resize(win, win_w, win_h);
evas_object_smart_callback_add(win, "delete,request", win_delete_request_cb,
sd);
evas_object_smart_callback_add(win, "moved", win_moved_cb, sd);
//Bg
Evas_Object *bg = elm_bg_add(win);
evas_object_show(bg);
elm_win_resize_object_add(win, bg);
//Layout
Evas_Object *layout = elm_layout_add(win);
elm_layout_file_set(layout, EDJE_PATH, "search");
evas_object_size_hint_weight_set(layout, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
evas_object_show(layout);
elm_win_resize_object_add(win, layout);
//Entry (find)
Evas_Object *entry_find = elm_entry_add(layout);
elm_entry_single_line_set(entry_find, EINA_TRUE);
elm_entry_scrollable_set(entry_find, EINA_TRUE);
evas_object_smart_callback_add(entry_find, "activated", find_activated_cb,
sd);
evas_object_size_hint_weight_set(entry_find, EVAS_HINT_EXPAND, 0);
evas_object_size_hint_align_set(entry_find, EVAS_HINT_FILL, 0);
evas_object_show(entry_find);
elm_object_focus_set(entry_find, EINA_TRUE);
elm_object_part_content_set(layout, "elm.swallow.find_entry", entry_find);
//Entry (replace)
Evas_Object *entry_replace = elm_entry_add(layout);
elm_entry_single_line_set(entry_replace, EINA_TRUE);
elm_entry_scrollable_set(entry_replace, EINA_TRUE);
evas_object_smart_callback_add(entry_replace, "activated",
replace_activated_cb, sd);
evas_object_size_hint_weight_set(entry_replace, EVAS_HINT_EXPAND,0);
evas_object_size_hint_align_set(entry_replace, EVAS_HINT_FILL, 0);
elm_object_part_content_set(layout, "elm.swallow.replace_entry",
entry_replace);
//Button (forward)
Evas_Object *btn_forward = elm_button_add(layout);
elm_object_text_set(btn_forward, "Forward");
evas_object_smart_callback_add(btn_forward, "clicked", forward_clicked_cb,
sd);
elm_object_part_content_set(layout, "elm.swallow.forward", btn_forward);
//Button (backward)
Evas_Object *btn_backward = elm_button_add(layout);
elm_object_text_set(btn_backward, "Backward");
evas_object_smart_callback_add(btn_backward, "clicked",
backward_clicked_cb, sd);
elm_object_part_content_set(layout, "elm.swallow.backward",
btn_backward);
//Button (replace)
Evas_Object *btn_replace = elm_button_add(layout);
elm_object_text_set(btn_replace, "Replace");
evas_object_smart_callback_add(btn_replace, "clicked",
replace_clicked_cb, sd);
elm_object_part_content_set(layout, "elm.swallow.replace", btn_replace);
//Button (replace all)
Evas_Object *btn_replace_all = elm_button_add(layout);
elm_object_text_set(btn_replace_all, "Replace All");
evas_object_smart_callback_add(btn_replace_all, "clicked",
replace_all_clicked_cb, sd);
elm_object_part_content_set(layout, "elm.swallow.replace_all",
btn_replace_all);
evas_object_show(win);
sd->win = win;
sd->layout = layout;
sd->en_find = entry_find;
sd->en_replace = entry_replace;
sd->entry = g_entry;
sd->pos = -1;
sd->forward = EINA_TRUE;
}
Eina_Bool
search_is_opened()
{
search_data *sd = g_sd;
return (sd ? EINA_TRUE : EINA_FALSE);
}
void
search_entry_register(Evas_Object *entry)
{
g_entry = entry;
}
void
search_close()
{
search_data *sd = g_sd;
if (!sd) return;
//Save last state
evas_object_geometry_get(sd->win, NULL, NULL, &win_w, &win_h);
elm_win_screen_position_get(sd->win, &win_x, &win_y);
evas_object_del(sd->win);
free(sd);
g_sd = NULL;
}