0
0
mirror of https://github.com/rkd77/elinks.git synced 2025-06-30 22:19:29 -04:00

[tabs] tab_manager

Needs more work. User must assign key for it.
This commit is contained in:
Witold Filipczyk 2025-01-04 14:24:33 +01:00
parent 90a7a2c5f8
commit ff14caac84
8 changed files with 462 additions and 2 deletions

View File

@ -124,6 +124,7 @@ ACTION_(MAIN, "submit-form-reload", SUBMIT_FORM_RELOAD, N__("Submit form and rel
ACTION_(MAIN, "tab-close", TAB_CLOSE, N__("Close tab"), 0),
ACTION_(MAIN, "tab-close-all-but-current", TAB_CLOSE_ALL_BUT_CURRENT, N__("Close all tabs but the current one"), 0),
ACTION_(MAIN, "tab-external-command", TAB_EXTERNAL_COMMAND, N__("Pass URI of current tab to external command"), ACTION_RESTRICT_ANONYMOUS | ACTION_REQUIRE_LOCATION),
ACTION_(MAIN, "tab-manager", TAB_MANAGER, N__("Open tab manager"), 0),
ACTION_(MAIN, "tab-menu", TAB_MENU, N__("Open the tab menu"), 0),
ACTION_(MAIN, "tab-move-left", TAB_MOVE_LEFT, N__("Move the current tab to the left"), 0),
ACTION_(MAIN, "tab-move-right", TAB_MOVE_RIGHT, N__("Move the current tab to the right"), 0),

View File

@ -1482,6 +1482,12 @@ static union option_info config_options_info[] = {
"tabs", OPT_ZERO,
N_("Window tabs settings.")),
INIT_OPT_INT("ui.tabs", N_("Display style"),
"display_type", OPT_ZERO, 0, 1, 0,
N_("What to display in tab manager dialog:\n"
"0 is URLs\n"
"1 is page titles")),
INIT_OPT_INT("ui.tabs", N_("Display tabs bar"),
"show_bar", OPT_ZERO, 0, 2, 1,
N_("Show tabs bar on the screen:\n"

View File

@ -3,6 +3,6 @@ include $(top_builddir)/Makefile.config
OBJS-$(CONFIG_EXMODE) += exmode.o
OBJS = document.o download.o edit.o info.o menu.o options.o progress.o status.o
OBJS = document.o download.o edit.o info.o menu.o options.o progress.o status.o tabs.o
include $(top_srcdir)/Makefile.lib

View File

@ -263,6 +263,7 @@ tab_menu(struct session *ses, int x, int y, int place_above_cursor)
if (tabs_count > 1) {
add_menu_action(&menu, N_("Nex~t tab"), ACT_MAIN_TAB_NEXT);
add_menu_action(&menu, N_("Pre~v tab"), ACT_MAIN_TAB_PREV);
add_menu_action(&menu, N_("Tab ~manager"), ACT_MAIN_TAB_MANAGER);
}
add_menu_action(&menu, N_("~Close tab"), ACT_MAIN_TAB_CLOSE);

View File

@ -1,4 +1,4 @@
if conf_data.get('CONFIG_EXMODE')
srcs += files('exmode.c')
endif
srcs += files('document.c', 'download.c', 'edit.c', 'info.c', 'menu.c', 'options.c', 'progress.c', 'status.c')
srcs += files('document.c', 'download.c', 'edit.c', 'info.c', 'menu.c', 'options.c', 'progress.c', 'status.c', 'tabs.c')

429
src/dialogs/tabs.c Normal file
View File

@ -0,0 +1,429 @@
/* tab manager dialogs */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <string.h>
#include "elinks.h"
#include "bfu/dialog.h"
#include "bfu/inphist.h"
#include "bookmarks/dialogs.h"
#include "dialogs/edit.h"
#include "dialogs/tabs.h"
#include "document/document.h"
#include "document/view.h"
#include "intl/libintl.h"
#include "main/object.h"
#include "protocol/uri.h"
#include "terminal/tab.h"
#include "terminal/terminal.h"
#include "util/conv.h"
#include "util/memory.h"
#include "util/string.h"
#include "viewer/text/view.h"
struct tab_item {
OBJECT_HEAD(struct tab_item);
struct listbox_item *box_item;
char *title;
char *url;
int i;
};
static char *tab_last_searched_title;
static char *tab_last_searched_url;
INIT_INPUT_HISTORY(tabs);
static struct tab_item *
init_tab_item(char *url, char *title, int i)
{
struct tab_item *tab_item = (struct tab_item *)mem_calloc(1, sizeof(*tab_item));
if (!tab_item) {
return NULL;
}
tab_item->i = i;
tab_item->title = stracpy(empty_string_or_(title));
if (!tab_item->title) {
mem_free(tab_item);
return NULL;
}
sanitize_title(tab_item->title);
tab_item->url = stracpy(url);
if (!tab_item->url || !sanitize_url(tab_item->url)) {
mem_free_if(tab_item->url);
mem_free(tab_item->title);
mem_free(tab_item);
return NULL;
}
tab_item->box_item = add_listbox_leaf(&tab_browser, NULL, tab_item);
if (!tab_item->box_item) {
mem_free(tab_item->url);
mem_free(tab_item->title);
mem_free(tab_item);
return NULL;
}
object_nolock(tab_item, "tab");
return tab_item;
}
static void
add_tab_item(char *url, char *title, int i)
{
struct tab_item *item = init_tab_item(url, title, i);
if (!item) {
return;
}
add_to_history_list(&tabs, item);
}
/* Implementation of the listbox operations */
static void
lock_tab_item(struct listbox_item *item)
{
}
static void
unlock_tab_item(struct listbox_item *item)
{
}
static int
is_tab_item_used(struct listbox_item *item)
{
return 0;
}
static char *
get_tab_item_text(struct listbox_item *box_item, struct terminal *term)
{
struct tab_item *item = (struct tab_item *)box_item->udata;
struct string info;
if (get_opt_int("ui.tabs.display_type", NULL) && *item->title) {
return stracpy(item->title);
}
if (!init_string(&info)) {
return NULL;
}
add_string_uri_to_string(&info, item->url, URI_PUBLIC);
return info.source;
}
static char *
get_tab_item_info(struct listbox_item *box_item, struct terminal *term)
{
struct tab_item *item = (struct tab_item *)box_item->udata;
struct string info;
if (box_item->type == BI_FOLDER) return NULL;
if (!init_string(&info)) return NULL;
add_format_to_string(&info, "%s: %s", _("Title", term), item->title);
add_format_to_string(&info, "\n%s: %s", _("URL", term), item->url);
return info.source;
}
static struct listbox_item *
get_tab_item_root(struct listbox_item *box_item)
{
return NULL;
}
static struct uri *
get_tab_item_uri(struct listbox_item *item)
{
struct tab_item *tab_item = (struct tab_item *)item->udata;
return get_uri(tab_item->url, URI_NONE);
}
static int
get_tab_item_number(struct listbox_item *item)
{
struct tab_item *tab_item = (struct tab_item *)item->udata;
return tab_item->i;
}
static int
can_delete_tab_item(struct listbox_item *item)
{
return 0;
}
static struct listbox_ops_messages tab_messages = {
/* cant_delete_item */
N_("Sorry, but tabs entry \"%s\" cannot be deleted."),
/* cant_delete_used_item */
N_("Sorry, but tabs entry \"%s\" is being used by something else."),
/* cant_delete_folder */
NULL,
/* cant_delete_used_folder */
NULL,
/* delete_marked_items_title */
N_("Delete marked tabs entries"),
/* delete_marked_items */
N_("Delete marked tabs entries?"),
/* delete_folder_title */
NULL,
/* delete_folder */
NULL,
/* delete_item_title */
N_("Delete tab entry"),
/* delete_item; xgettext:c-format */
N_("Delete this tab entry?"),
/* clear_all_items_title */
N_("Clear all tabs entries"),
/* clear_all_items_title */
N_("Do you really want to remove all tabs entries?"),
};
static const struct listbox_ops tab_listbox_ops = {
lock_tab_item,
unlock_tab_item,
is_tab_item_used,
get_tab_item_text,
get_tab_item_info,
get_tab_item_uri,
get_tab_item_root,
NULL, // search
can_delete_tab_item,
NULL, // delete
NULL, // draw
&tab_messages,
};
/* Searching: */
static int
tab_simple_search(char *search_url, char *search_title)
{
struct tab_item *tab_item;
if (!search_title || !search_url)
return 0;
/* Memorize last searched title */
mem_free_set(&tab_last_searched_title, stracpy(search_title));
if (!tab_last_searched_title) return 0;
/* Memorize last searched url */
mem_free_set(&tab_last_searched_url, stracpy(search_url));
if (!tab_last_searched_url) return 0;
if (!*search_title && !*search_url) {
/* No search terms, make all entries visible. */
foreach (tab_item, tabs.entries) {
tab_item->box_item->visible = 1;
}
return 1;
}
foreach (tab_item, tabs.entries) {
/* Make matching entries visible, hide others. */
if ((*search_title
&& strcasestr((const char *)tab_item->title, (const char *)search_title))
|| (*search_url
&& c_strcasestr((const char *)tab_item->url, (const char *)search_url))) {
tab_item->box_item->visible = 1;
} else {
tab_item->box_item->visible = 0;
}
}
return 1;
}
static void
tabs_search_do(void *data)
{
struct dialog *dlg = (struct dialog *)data;
struct listbox_item *item = (struct listbox_item *)tab_browser.root.child.next;
struct listbox_data *box;
if (!tab_simple_search((char *)dlg->widgets[1].data, (char *)dlg->widgets[0].data)) return;
if (list_empty(tab_browser.root.child)) return;
/* Shouldn't we rather do this only for the specific listbox_data box
* in dlg->widget->data so only the current dialog is updated? --jonas */
foreach (box, tab_browser.boxes) {
box->top = item;
box->sel = box->top;
}
}
static void
launch_search_dialog(struct terminal *term, struct dialog_data *parent,
struct session *ses)
{
do_edit_dialog(term, 1, N_("Search tabs"), tab_last_searched_title,
tab_last_searched_url, ses, parent, tabs_search_do,
NULL, NULL, EDIT_DLG_SEARCH);
}
static widget_handler_status_T
push_search_button(struct dialog_data *dlg_data, struct widget_data *widget_data)
{
launch_search_dialog(dlg_data->win->term, dlg_data,
(struct session *) dlg_data->dlg->udata);
return EVENT_PROCESSED;
}
/* Toggling: */
static widget_handler_status_T
push_toggle_display_button(struct dialog_data *dlg_data, struct widget_data *widget_data)
{
int *display_type;
display_type = &get_opt_int("ui.tabs.display_type", NULL);
*display_type = !*display_type;
update_hierbox_browser(&tab_browser);
return EVENT_PROCESSED;
}
static widget_handler_status_T
push_goto_button(struct dialog_data *dlg_data,
struct widget_data *button)
{
struct listbox_data *box = get_dlg_listbox_data(dlg_data);
struct listbox_item *item = box->sel;
struct terminal *term = dlg_data->win->term;
if (!item) return EVENT_PROCESSED;
if (item->type == BI_LEAF) {
int tab = get_tab_item_number(item);
switch_to_tab(term, tab, -1);
}
/* Close the dialog */
delete_window(dlg_data->win);
return EVENT_PROCESSED;
}
static widget_handler_status_T
push_close_button(struct dialog_data *dlg_data,
struct widget_data *button)
{
struct listbox_data *box = get_dlg_listbox_data(dlg_data);
struct listbox_item *item = box->sel;
struct session *ses = (struct session *)dlg_data->dlg->udata;
struct terminal *term = dlg_data->win->term;
if (!item) return EVENT_PROCESSED;
if (item->type == BI_LEAF) {
int num = get_tab_item_number(item);
switch_to_tab(term, num, -1);
}
/* Close the dialog */
delete_window(dlg_data->win);
return EVENT_PROCESSED;
}
/* Bookmarking: */
#ifdef CONFIG_BOOKMARKS
static widget_handler_status_T
push_bookmark_button(struct dialog_data *dlg_data,
struct widget_data *some_useless_info_button)
{
struct listbox_data *box = get_dlg_listbox_data(dlg_data);
struct terminal *term = dlg_data->win->term;
struct tab_item *tab_item;
if (!box->sel) return EVENT_PROCESSED;
tab_item = (struct tab_item *)box->sel->udata;
if (!tab_item) return EVENT_PROCESSED;
launch_bm_add_dialog(term, NULL, NULL,
tab_item->title, tab_item->url);
return EVENT_PROCESSED;
}
#endif
/* The global tabs manager: */
static const struct hierbox_browser_button tabs_buttons[] = {
/* [gettext_accelerator_context(.globhist_buttons)] */
{ N_("~Goto"), push_goto_button, 1 },
#ifdef CONFIG_BOOKMARKS
{ N_("~Bookmark"), push_bookmark_button, 0 },
#endif
//{ N_("~Close"), push_close_button, 1 },
{ N_("~Search"), push_search_button, 1 },
{ N_("~Toggle display url/title"), push_toggle_display_button, 1 },
};
struct_hierbox_browser(
tab_browser,
N_("Tabs manager"),
tabs_buttons,
&tab_listbox_ops
);
static void
populate_tabs_data(struct session *ses)
{
struct terminal *term = ses->tab->term;
int tab_count = number_of_tabs(term);
int i;
struct tab_item *item, *next;
foreachsafe (item, next, tabs.entries) {
del_from_history_list(&tabs, item);
done_listbox_item(&tab_browser, item->box_item);
mem_free_if(item->url);
mem_free_if(item->title);
}
for (i = tab_count - 1; i >= 0; i--) {
struct window *tab = get_tab_by_number(term, i);
struct session *tab_ses = (struct session *)tab->data;
struct document_view *doc_view = tab_ses ? current_frame(tab_ses) : NULL;
char *url = "";
char *title = "";
if (doc_view) {
if (doc_view->document->title) {
title = doc_view->document->title;
}
if (doc_view->vs && doc_view->vs->uri) {
url = struri(doc_view->vs->uri);
}
}
add_tab_item(url, title, i);
}
}
void
tab_manager(struct session *ses)
{
mem_free_set(&tab_last_searched_title, NULL);
mem_free_set(&tab_last_searched_url, NULL);
populate_tabs_data(ses);
hierbox_browser(&tab_browser, ses);
}

18
src/dialogs/tabs.h Normal file
View File

@ -0,0 +1,18 @@
#ifndef EL__DIALOGS_TABS_H
#define EL__DIALOGS_TABS_H
#include "bfu/hierbox.h"
#include "session/session.h"
#ifdef __cplusplus
extern "C" {
#endif
extern struct hierbox_browser tab_browser;
void tab_manager(struct session *);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -23,6 +23,7 @@
#include "dialogs/menu.h"
#include "dialogs/options.h"
#include "dialogs/status.h"
#include "dialogs/tabs.h"
#include "document/document.h"
#include "document/view.h"
#ifdef CONFIG_ECMASCRIPT
@ -717,6 +718,10 @@ do_action(struct session *ses, main_action_T action_id, int verbose)
switch_current_tab(ses, -1);
break;
case ACT_MAIN_TAB_MANAGER:
tab_manager(ses);
break;
case ACT_MAIN_TERMINAL_RESIZE:
resize_terminal_dialog(term);
break;