/* SPDX-FileCopyrightText: 2022-2024 - Sébastien Wilmet <swilmet@gnome.org>
 * SPDX-License-Identifier: LGPL-3.0-or-later
 */

#include "config.h"
#include "tepl-prefs-dialog.h"
#include <glib/gi18n-lib.h>
#include "tepl-abstract-factory.h"

/**
 * SECTION:prefs-dialog
 * @Short_description: Preferences dialog
 * @Title: TeplPrefsDialog
 *
 * #TeplPrefsDialog is a subclass of #GtkDialog for configuring the preferences
 * of an application.
 */

/* By sub-classing GtkDialog, there is the Escape keyboard shortcut to close the
 * dialog (which is what we want).
 */

struct _TeplPrefsDialogPrivate
{
	gint something;
};

enum
{
	SIGNAL_RESET_ALL,
	N_SIGNALS
};

static guint signals[N_SIGNALS];
static TeplPrefsDialog *singleton = NULL;

G_DEFINE_TYPE_WITH_PRIVATE (TeplPrefsDialog, tepl_prefs_dialog, GTK_TYPE_DIALOG)

static void
tepl_prefs_dialog_finalize (GObject *object)
{
	if (singleton == TEPL_PREFS_DIALOG (object))
	{
		singleton = NULL;
	}

	G_OBJECT_CLASS (tepl_prefs_dialog_parent_class)->finalize (object);
}

static gboolean
tepl_prefs_dialog_delete_event (GtkWidget   *widget,
				GdkEventAny *event)
{
	gtk_widget_hide (widget);
	return GDK_EVENT_STOP;
}

static void
tepl_prefs_dialog_class_init (TeplPrefsDialogClass *klass)
{
	GObjectClass *object_class = G_OBJECT_CLASS (klass);
	GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);

	object_class->finalize = tepl_prefs_dialog_finalize;
	widget_class->delete_event = tepl_prefs_dialog_delete_event;

	/**
	 * TeplPrefsDialog::reset-all:
	 * @prefs_dialog: the #TeplPrefsDialog emitting the signal.
	 *
	 * The ::reset-all signal is emitted when the user has requested to
	 * reset all preferences.
	 *
	 * Applications should connect to this signal to perform the operation.
	 * tepl_settings_reset_all() may be useful for that.
	 *
	 * See tepl_prefs_dialog_add_reset_all_button().
	 *
	 * Since: 6.13
	 */
	signals[SIGNAL_RESET_ALL] =
		g_signal_new ("reset-all",
			      G_TYPE_FROM_CLASS (klass),
			      G_SIGNAL_RUN_FIRST,
			      0, NULL, NULL, NULL,
			      G_TYPE_NONE, 0);
}

static void
tepl_prefs_dialog_init (TeplPrefsDialog *dialog)
{
	GtkWidget *content_area;

	dialog->priv = tepl_prefs_dialog_get_instance_private (dialog);

	gtk_window_set_title (GTK_WINDOW (dialog), _("Preferences"));

	/* Ideally this should be hide-when-parent-destroyed, but it isn't
	 * implemented by GTK. A utils function could be implemented, but it's
	 * more code (so more chances to get it wrong), and it doesn't really
	 * worth it.
	 *
	 * So, keep things simple.
	 *
	 * When the app has several main windows opened, but on different
	 * workspaces, it would be strange to keep the TeplPrefsDialog visible
	 * when its parent is closed. So it needs to be hidden or destroyed.
	 * Hidden is slightly better because a preferences dialog usually has a
	 * GtkNotebook inside (or something similar), so it's better to keep the
	 * same tab when showing again the preferences dialog.
	 */
	gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog), TRUE);

	content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));

	/* When packing a GtkNotebook inside the content area, we don't want any
	 * margin around the GtkNotebook. More generally, we can also control
	 * the margins that we want with what we pack into the content area.
	 */
	gtk_container_set_border_width (GTK_CONTAINER (content_area), 0);
}

/**
 * tepl_prefs_dialog_new:
 *
 * Returns: (transfer floating): a new #TeplPrefsDialog.
 * Since: 6.13
 */
TeplPrefsDialog *
tepl_prefs_dialog_new (void)
{
	return g_object_new (TEPL_TYPE_PREFS_DIALOG,
			     "use-header-bar", TRUE,
			     NULL);
}

/**
 * tepl_prefs_dialog_get_singleton:
 *
 * The singleton instance is created with
 * tepl_abstract_factory_create_prefs_dialog().
 *
 * Returns: (transfer none): the #TeplPrefsDialog singleton instance.
 * Since: 6.2
 */
TeplPrefsDialog *
tepl_prefs_dialog_get_singleton (void)
{
	if (singleton == NULL)
	{
		TeplAbstractFactory *factory;

		factory = tepl_abstract_factory_get_singleton ();
		singleton = tepl_abstract_factory_create_prefs_dialog (factory);
	}

	return singleton;
}

void
_tepl_prefs_dialog_unref_singleton (void)
{
	if (singleton != NULL)
	{
		gtk_widget_destroy (GTK_WIDGET (singleton));
	}
}

/**
 * tepl_prefs_dialog_show_for_parent:
 * @dialog: a #TeplPrefsDialog.
 * @parent_window: the parent #GtkWindow.
 *
 * This function sets the #GtkWindow:transient-for property and presents
 * @dialog.
 *
 * Since: 6.2
 */
void
tepl_prefs_dialog_show_for_parent (TeplPrefsDialog *dialog,
				   GtkWindow       *parent_window)
{
	g_return_if_fail (TEPL_IS_PREFS_DIALOG (dialog));
	g_return_if_fail (GTK_IS_WINDOW (parent_window));

	gtk_window_set_transient_for (GTK_WINDOW (dialog), parent_window);
	gtk_window_present (GTK_WINDOW (dialog));
}

static void
reset_all_confirm_dialog_response_cb (GtkDialog       *confirm_dialog,
				      gint             response_id,
				      TeplPrefsDialog *dialog)
{
	if (response_id == GTK_RESPONSE_YES)
	{
		g_signal_emit (dialog, signals[SIGNAL_RESET_ALL], 0);
	}

	gtk_widget_destroy (GTK_WIDGET (confirm_dialog));
}

static void
reset_button_clicked_cb (GtkButton       *reset_button,
			 TeplPrefsDialog *dialog)
{
	GtkWidget *confirm_dialog;

	confirm_dialog = gtk_message_dialog_new (GTK_WINDOW (dialog),
						 GTK_DIALOG_MODAL |
						 GTK_DIALOG_DESTROY_WITH_PARENT,
						 GTK_MESSAGE_QUESTION,
						 GTK_BUTTONS_NONE,
						 _("Do you really want to reset all preferences?"));

	gtk_dialog_add_button (GTK_DIALOG (confirm_dialog),
			       _("_Cancel"),
			       GTK_RESPONSE_CANCEL);

	gtk_dialog_add_button (GTK_DIALOG (confirm_dialog),
			       _("_Reset All"),
			       GTK_RESPONSE_YES);

	g_signal_connect_object (confirm_dialog,
				 "response",
				 G_CALLBACK (reset_all_confirm_dialog_response_cb),
				 dialog,
				 G_CONNECT_DEFAULT);

	gtk_widget_show_all (confirm_dialog);
}

/**
 * tepl_prefs_dialog_add_reset_all_button:
 * @dialog: a #TeplPrefsDialog.
 *
 * Adds a “Reset All” button. When the button is clicked and the user confirms,
 * the #TeplPrefsDialog::reset-all signal is emitted.
 *
 * Since: 6.13
 */
void
tepl_prefs_dialog_add_reset_all_button (TeplPrefsDialog *dialog)
{
	GtkWidget *header_bar;
	GtkWidget *reset_button;

	g_return_if_fail (TEPL_IS_PREFS_DIALOG (dialog));

	header_bar = gtk_dialog_get_header_bar (GTK_DIALOG (dialog));
	g_return_if_fail (header_bar != NULL);

	reset_button = gtk_button_new_with_mnemonic (_("_Reset All…"));
	gtk_widget_set_tooltip_text (reset_button, _("Reset all preferences"));
	gtk_widget_show (reset_button);

	gtk_header_bar_pack_start (GTK_HEADER_BAR (header_bar), reset_button);

	g_signal_connect_object (reset_button,
				 "clicked",
				 G_CALLBACK (reset_button_clicked_cb),
				 dialog,
				 G_CONNECT_DEFAULT);
}
