mirror of https://github.com/GNOME/gimp.git
Bug 706309 - Add a “Save As” button to the “Quit GIMP” dialog
Add GimpCellRendererButton and use it to add a "Save" icon to each row of dirty images. Click invokes the "edit-save" action, shift-click invokes "edit-save-as". Also add a tooltip for the icon button. Involves minor changes to GimpContainerTreeView to allow GimpCellRendererButton to be added, and to allow external "query-tooltip" handlers to run.
This commit is contained in:
parent
aa0afe0d01
commit
0089a017f0
|
@ -37,7 +37,9 @@
|
|||
#include "display/gimpdisplay.h"
|
||||
#include "display/gimpdisplay-foreach.h"
|
||||
#include "display/gimpdisplayshell.h"
|
||||
#include "display/gimpimagewindow.h"
|
||||
|
||||
#include "widgets/gimpcellrendererbutton.h"
|
||||
#include "widgets/gimpcontainertreestore.h"
|
||||
#include "widgets/gimpcontainertreeview.h"
|
||||
#include "widgets/gimpcontainerview.h"
|
||||
|
@ -45,6 +47,7 @@
|
|||
#include "widgets/gimphelp-ids.h"
|
||||
#include "widgets/gimpmessagebox.h"
|
||||
#include "widgets/gimpmessagedialog.h"
|
||||
#include "widgets/gimpuimanager.h"
|
||||
#include "widgets/gimpviewrenderer.h"
|
||||
#include "widgets/gimpwidgets-utils.h"
|
||||
|
||||
|
@ -57,20 +60,22 @@ typedef struct _QuitDialog QuitDialog;
|
|||
|
||||
struct _QuitDialog
|
||||
{
|
||||
Gimp *gimp;
|
||||
GimpContainer *images;
|
||||
GimpContext *context;
|
||||
Gimp *gimp;
|
||||
GimpContainer *images;
|
||||
GimpContext *context;
|
||||
|
||||
gboolean do_quit;
|
||||
gboolean do_quit;
|
||||
|
||||
GtkWidget *dialog;
|
||||
GtkWidget *ok_button;
|
||||
GimpMessageBox *box;
|
||||
GtkWidget *lost_label;
|
||||
GtkWidget *hint_label;
|
||||
GtkWidget *dialog;
|
||||
GimpContainerTreeView *tree_view;
|
||||
GtkTreeViewColumn *save_column;
|
||||
GtkWidget *ok_button;
|
||||
GimpMessageBox *box;
|
||||
GtkWidget *lost_label;
|
||||
GtkWidget *hint_label;
|
||||
|
||||
guint accel_key;
|
||||
GdkModifierType accel_mods;
|
||||
guint accel_key;
|
||||
GdkModifierType accel_mods;
|
||||
};
|
||||
|
||||
|
||||
|
@ -98,7 +103,16 @@ static void quit_close_all_dialog_name_cell_func (GtkTreeViewColumn *t
|
|||
GtkTreeModel *tree_model,
|
||||
GtkTreeIter *iter,
|
||||
gpointer data);
|
||||
|
||||
static void quit_close_all_dialog_save_clicked (GtkCellRenderer *cell,
|
||||
const gchar *path,
|
||||
GdkModifierType state,
|
||||
QuitDialog *dialog);
|
||||
static gboolean quit_close_all_dialog_query_tooltip (GtkWidget *widget,
|
||||
gint x,
|
||||
gint y,
|
||||
gboolean keyboard_tip,
|
||||
GtkTooltip *tooltip,
|
||||
QuitDialog *dialog);
|
||||
|
||||
/* public functions */
|
||||
|
||||
|
@ -121,6 +135,7 @@ quit_close_all_dialog_new (Gimp *gimp,
|
|||
QuitDialog *dialog;
|
||||
GtkWidget *view;
|
||||
GimpContainerTreeView *tree_view;
|
||||
GtkTreeViewColumn *column;
|
||||
GtkCellRenderer *renderer;
|
||||
GtkWidget *dnd_widget;
|
||||
GtkAccelGroup *accel_group;
|
||||
|
@ -187,15 +202,35 @@ quit_close_all_dialog_new (Gimp *gimp,
|
|||
|
||||
view = gimp_container_tree_view_new (dialog->images, dialog->context,
|
||||
view_size, 1);
|
||||
tree_view = GIMP_CONTAINER_TREE_VIEW (view);
|
||||
gimp_container_box_set_size_request (GIMP_CONTAINER_BOX (view),
|
||||
-1,
|
||||
rows * (view_size + 2));
|
||||
|
||||
dialog->tree_view = tree_view = GIMP_CONTAINER_TREE_VIEW (view);
|
||||
|
||||
gtk_tree_view_column_set_expand (tree_view->main_column, TRUE);
|
||||
|
||||
renderer = gimp_container_tree_view_get_name_cell (tree_view);
|
||||
gtk_tree_view_column_set_cell_data_func (tree_view->main_column,
|
||||
renderer,
|
||||
quit_close_all_dialog_name_cell_func,
|
||||
NULL, NULL);
|
||||
gimp_container_box_set_size_request (GIMP_CONTAINER_BOX (view),
|
||||
-1,
|
||||
rows * (view_size + 2));
|
||||
|
||||
dialog->save_column = column = gtk_tree_view_column_new ();
|
||||
renderer = gimp_cell_renderer_button_new ();
|
||||
g_object_set (renderer,
|
||||
"icon-name", "document-save",
|
||||
NULL);
|
||||
gtk_tree_view_column_pack_end (column, renderer, FALSE);
|
||||
gtk_tree_view_column_set_attributes (column, renderer, NULL);
|
||||
|
||||
gtk_tree_view_append_column (tree_view->view, column);
|
||||
gimp_container_tree_view_add_toggle_cell (tree_view, renderer);
|
||||
|
||||
g_signal_connect (renderer, "clicked",
|
||||
G_CALLBACK (quit_close_all_dialog_save_clicked),
|
||||
dialog);
|
||||
|
||||
gtk_box_pack_start (GTK_BOX (dialog->box), view, TRUE, TRUE, 0);
|
||||
gtk_widget_show (view);
|
||||
|
||||
|
@ -208,6 +243,10 @@ quit_close_all_dialog_new (Gimp *gimp,
|
|||
(GimpDndDragViewableFunc) gimp_dnd_get_drag_data,
|
||||
NULL);
|
||||
|
||||
g_signal_connect (tree_view->view, "query-tooltip",
|
||||
G_CALLBACK (quit_close_all_dialog_query_tooltip),
|
||||
dialog);
|
||||
|
||||
if (do_quit)
|
||||
dialog->lost_label = gtk_label_new (_("If you quit GIMP now, "
|
||||
"these changes will be lost."));
|
||||
|
@ -436,3 +475,103 @@ quit_close_all_dialog_name_cell_func (GtkTreeViewColumn *tree_column,
|
|||
g_object_unref (renderer);
|
||||
g_free (name);
|
||||
}
|
||||
|
||||
static void
|
||||
quit_close_all_dialog_save_clicked (GtkCellRenderer *cell,
|
||||
const gchar *path_str,
|
||||
GdkModifierType state,
|
||||
QuitDialog *dialog)
|
||||
{
|
||||
GtkTreePath *path = gtk_tree_path_new_from_string (path_str);
|
||||
GtkTreeIter iter;
|
||||
|
||||
if (gtk_tree_model_get_iter (dialog->tree_view->model, &iter, path))
|
||||
{
|
||||
GimpViewRenderer *renderer;
|
||||
GimpImage *image;
|
||||
GList *list;
|
||||
|
||||
gtk_tree_model_get (dialog->tree_view->model, &iter,
|
||||
GIMP_CONTAINER_TREE_STORE_COLUMN_RENDERER, &renderer,
|
||||
-1);
|
||||
|
||||
image = GIMP_IMAGE (renderer->viewable);
|
||||
g_object_unref (renderer);
|
||||
|
||||
for (list = gimp_get_display_iter (dialog->gimp);
|
||||
list;
|
||||
list = g_list_next (list))
|
||||
{
|
||||
GimpDisplay *display = list->data;
|
||||
|
||||
if (gimp_display_get_image (display) == image)
|
||||
{
|
||||
GimpDisplayShell *shell = gimp_display_get_shell (display);
|
||||
GimpImageWindow *window = gimp_display_shell_get_window (shell);
|
||||
|
||||
if (window)
|
||||
{
|
||||
GimpUIManager *manager;
|
||||
|
||||
manager = gimp_image_window_get_ui_manager (window);
|
||||
|
||||
gimp_display_shell_present (shell);
|
||||
|
||||
if (state & GDK_SHIFT_MASK)
|
||||
{
|
||||
gimp_ui_manager_activate_action (manager, "file",
|
||||
"file-save-as");
|
||||
}
|
||||
else
|
||||
{
|
||||
gimp_ui_manager_activate_action (manager, "file",
|
||||
"file-save");
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
quit_close_all_dialog_query_tooltip (GtkWidget *widget,
|
||||
gint x,
|
||||
gint y,
|
||||
gboolean keyboard_tip,
|
||||
GtkTooltip *tooltip,
|
||||
QuitDialog *dialog)
|
||||
{
|
||||
GtkTreePath *path;
|
||||
gboolean show_tip = FALSE;
|
||||
|
||||
if (gtk_tree_view_get_tooltip_context (GTK_TREE_VIEW (widget), &x, &y,
|
||||
keyboard_tip,
|
||||
NULL, &path, NULL))
|
||||
{
|
||||
GtkTreeViewColumn *column = NULL;
|
||||
|
||||
gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget), x, y,
|
||||
NULL, &column, NULL, NULL);
|
||||
|
||||
if (column == dialog->save_column)
|
||||
{
|
||||
gchar *tip = g_strconcat (_("Save this image"), "\n<b>",
|
||||
gimp_get_mod_string (GDK_SHIFT_MASK),
|
||||
"</b> ", _("Save as"),
|
||||
NULL);
|
||||
|
||||
gtk_tooltip_set_markup (tooltip, tip);
|
||||
gtk_tree_view_set_tooltip_row (GTK_TREE_VIEW (widget), tooltip, path);
|
||||
|
||||
g_free (tip);
|
||||
|
||||
show_tip = TRUE;
|
||||
}
|
||||
|
||||
gtk_tree_path_free (path);
|
||||
}
|
||||
|
||||
return show_tip;
|
||||
}
|
||||
|
|
|
@ -43,6 +43,8 @@ libappwidgets_a_sources = \
|
|||
gimpbufferview.h \
|
||||
gimpcairo-wilber.c \
|
||||
gimpcairo-wilber.h \
|
||||
gimpcellrendererbutton.c \
|
||||
gimpcellrendererbutton.h \
|
||||
gimpcellrendererdashes.c \
|
||||
gimpcellrendererdashes.h \
|
||||
gimpcellrendererviewable.c \
|
||||
|
|
|
@ -0,0 +1,143 @@
|
|||
/* GIMP - The GNU Image Manipulation Program
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* gimpcellrendererbutton.c
|
||||
* Copyright (C) 2016 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "widgets-types.h"
|
||||
|
||||
#include "core/gimpmarshal.h"
|
||||
|
||||
#include "gimpcellrendererbutton.h"
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
CLICKED,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
|
||||
static gboolean gimp_cell_renderer_button_activate (GtkCellRenderer *cell,
|
||||
GdkEvent *event,
|
||||
GtkWidget *widget,
|
||||
const gchar *path,
|
||||
GdkRectangle *background_area,
|
||||
GdkRectangle *cell_area,
|
||||
GtkCellRendererState flags);
|
||||
|
||||
|
||||
G_DEFINE_TYPE (GimpCellRendererButton, gimp_cell_renderer_button,
|
||||
GTK_TYPE_CELL_RENDERER_PIXBUF)
|
||||
|
||||
#define parent_class gimp_cell_renderer_button_parent_class
|
||||
|
||||
static guint button_cell_signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
|
||||
static void
|
||||
gimp_cell_renderer_button_class_init (GimpCellRendererButtonClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (klass);
|
||||
|
||||
/**
|
||||
* GimpCellRendererButton::clicked:
|
||||
* @cell:
|
||||
* @path:
|
||||
* @state:
|
||||
*
|
||||
* Called on a button cell when it is clicked.
|
||||
**/
|
||||
button_cell_signals[CLICKED] =
|
||||
g_signal_new ("clicked",
|
||||
G_OBJECT_CLASS_TYPE (object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (GimpCellRendererButtonClass, clicked),
|
||||
NULL, NULL,
|
||||
gimp_marshal_VOID__STRING_FLAGS,
|
||||
G_TYPE_NONE, 2,
|
||||
G_TYPE_STRING,
|
||||
GDK_TYPE_MODIFIER_TYPE);
|
||||
|
||||
cell_class->activate = gimp_cell_renderer_button_activate;
|
||||
|
||||
klass->clicked = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_cell_renderer_button_init (GimpCellRendererButton *cell_button)
|
||||
{
|
||||
g_object_set (cell_button,
|
||||
"mode", GTK_CELL_RENDERER_MODE_ACTIVATABLE,
|
||||
"xpad", 2,
|
||||
"ypad", 2,
|
||||
"follow-state", TRUE,
|
||||
"stock-size", GTK_ICON_SIZE_BUTTON,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gimp_cell_renderer_button_activate (GtkCellRenderer *cell,
|
||||
GdkEvent *event,
|
||||
GtkWidget *widget,
|
||||
const gchar *path,
|
||||
GdkRectangle *background_area,
|
||||
GdkRectangle *cell_area,
|
||||
GtkCellRendererState flags)
|
||||
{
|
||||
GimpCellRendererButton *cell_button = GIMP_CELL_RENDERER_BUTTON (cell);
|
||||
GdkModifierType state = 0;
|
||||
|
||||
if (event && ((GdkEventAny *) event)->type == GDK_BUTTON_PRESS)
|
||||
state = ((GdkEventButton *) event)->state;
|
||||
|
||||
if (! event ||
|
||||
(((GdkEventAny *) event)->type == GDK_BUTTON_PRESS &&
|
||||
((GdkEventButton *) event)->button == 1))
|
||||
{
|
||||
gimp_cell_renderer_button_clicked (cell_button, path, state);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/* public functions */
|
||||
|
||||
GtkCellRenderer *
|
||||
gimp_cell_renderer_button_new (void)
|
||||
{
|
||||
return g_object_new (GIMP_TYPE_CELL_RENDERER_BUTTON, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
gimp_cell_renderer_button_clicked (GimpCellRendererButton *cell,
|
||||
const gchar *path,
|
||||
GdkModifierType state)
|
||||
{
|
||||
g_return_if_fail (GIMP_IS_CELL_RENDERER_BUTTON (cell));
|
||||
g_return_if_fail (path != NULL);
|
||||
|
||||
g_signal_emit (cell, button_cell_signals[CLICKED], 0, path, state);
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
/* GIMP - The GNU Image Manipulation Program
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* gimpcellrendererbutton.h
|
||||
* Copyright (C) 2016 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __GIMP_CELL_RENDERER_BUTTON_H__
|
||||
#define __GIMP_CELL_RENDERER_BUTTON_H__
|
||||
|
||||
|
||||
#define GIMP_TYPE_CELL_RENDERER_BUTTON (gimp_cell_renderer_button_get_type ())
|
||||
#define GIMP_CELL_RENDERER_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_CELL_RENDERER_BUTTON, GimpCellRendererButton))
|
||||
#define GIMP_CELL_RENDERER_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_CELL_RENDERER_BUTTON, GimpCellRendererButtonClass))
|
||||
#define GIMP_IS_CELL_RENDERER_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_CELL_RENDERER_BUTTON))
|
||||
#define GIMP_IS_CELL_RENDERER_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_CELL_RENDERER_BUTTON))
|
||||
#define GIMP_CELL_RENDERER_BUTTON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_CELL_RENDERER_BUTTON, GimpCellRendererButtonClass))
|
||||
|
||||
|
||||
typedef struct _GimpCellRendererButtonClass GimpCellRendererButtonClass;
|
||||
|
||||
struct _GimpCellRendererButton
|
||||
{
|
||||
GtkCellRendererPixbuf parent_instance;
|
||||
};
|
||||
|
||||
struct _GimpCellRendererButtonClass
|
||||
{
|
||||
GtkCellRendererPixbufClass parent_class;
|
||||
|
||||
void (* clicked) (GimpCellRendererButton *cell,
|
||||
const gchar *path,
|
||||
GdkModifierType state);
|
||||
};
|
||||
|
||||
|
||||
GType gimp_cell_renderer_button_get_type (void) G_GNUC_CONST;
|
||||
|
||||
GtkCellRenderer * gimp_cell_renderer_button_new (void);
|
||||
|
||||
void gimp_cell_renderer_button_clicked (GimpCellRendererButton *cell,
|
||||
const gchar *path,
|
||||
GdkModifierType state);
|
||||
|
||||
|
||||
#endif /* __GIMP_CELL_RENDERER_BUTTON_H__ */
|
|
@ -35,6 +35,7 @@
|
|||
#include "core/gimpmarshal.h"
|
||||
#include "core/gimpviewable.h"
|
||||
|
||||
#include "gimpcellrendererbutton.h"
|
||||
#include "gimpcellrendererviewable.h"
|
||||
#include "gimpcontainertreestore.h"
|
||||
#include "gimpcontainertreeview.h"
|
||||
|
@ -321,9 +322,12 @@ gimp_container_tree_view_constructed (GObject *object)
|
|||
G_CALLBACK (gimp_container_tree_view_drag_data_received),
|
||||
tree_view);
|
||||
|
||||
g_signal_connect (tree_view->view, "query-tooltip",
|
||||
G_CALLBACK (gimp_container_tree_view_tooltip),
|
||||
tree_view);
|
||||
/* connect_after so external code can connect to "query-tooltip" too
|
||||
* and override the default tip
|
||||
*/
|
||||
g_signal_connect_after (tree_view->view, "query-tooltip",
|
||||
G_CALLBACK (gimp_container_tree_view_tooltip),
|
||||
tree_view);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -520,7 +524,8 @@ gimp_container_tree_view_add_toggle_cell (GimpContainerTreeView *tree_view,
|
|||
GtkCellRenderer *cell)
|
||||
{
|
||||
g_return_if_fail (GIMP_IS_CONTAINER_TREE_VIEW (tree_view));
|
||||
g_return_if_fail (GIMP_IS_CELL_RENDERER_TOGGLE (cell));
|
||||
g_return_if_fail (GIMP_IS_CELL_RENDERER_TOGGLE (cell) ||
|
||||
GIMP_IS_CELL_RENDERER_BUTTON (cell));
|
||||
|
||||
tree_view->priv->toggle_cells = g_list_prepend (tree_view->priv->toggle_cells,
|
||||
cell);
|
||||
|
@ -1043,7 +1048,7 @@ gimp_container_tree_view_button_press (GtkWidget *widget,
|
|||
&path, &column, NULL, NULL))
|
||||
{
|
||||
GimpViewRenderer *renderer;
|
||||
GimpCellRendererToggle *toggled_cell = NULL;
|
||||
GtkCellRenderer *toggled_cell = NULL;
|
||||
GimpCellRendererViewable *clicked_cell = NULL;
|
||||
GtkCellRenderer *edit_cell = NULL;
|
||||
GdkRectangle column_area;
|
||||
|
@ -1098,7 +1103,7 @@ gimp_container_tree_view_button_press (GtkWidget *widget,
|
|||
g_list_free (cells);
|
||||
}
|
||||
|
||||
toggled_cell = (GimpCellRendererToggle *)
|
||||
toggled_cell =
|
||||
gimp_container_tree_view_find_click_cell (widget,
|
||||
tree_view->priv->toggle_cells,
|
||||
column, &column_area,
|
||||
|
@ -1181,9 +1186,18 @@ gimp_container_tree_view_button_press (GtkWidget *widget,
|
|||
|
||||
if (toggled_cell)
|
||||
{
|
||||
gimp_cell_renderer_toggle_clicked (toggled_cell,
|
||||
path_str,
|
||||
bevent->state);
|
||||
if (GIMP_IS_CELL_RENDERER_TOGGLE (toggled_cell))
|
||||
{
|
||||
gimp_cell_renderer_toggle_clicked (GIMP_CELL_RENDERER_TOGGLE (toggled_cell),
|
||||
path_str,
|
||||
bevent->state);
|
||||
}
|
||||
else if (GIMP_IS_CELL_RENDERER_BUTTON (toggled_cell))
|
||||
{
|
||||
gimp_cell_renderer_button_clicked (GIMP_CELL_RENDERER_BUTTON (toggled_cell),
|
||||
path_str,
|
||||
bevent->state);
|
||||
}
|
||||
}
|
||||
else if (clicked_cell)
|
||||
{
|
||||
|
|
|
@ -240,6 +240,7 @@ typedef struct _GimpViewRendererVectors GimpViewRendererVectors;
|
|||
|
||||
/* cell renderers */
|
||||
|
||||
typedef struct _GimpCellRendererButton GimpCellRendererButton;
|
||||
typedef struct _GimpCellRendererDashes GimpCellRendererDashes;
|
||||
typedef struct _GimpCellRendererViewable GimpCellRendererViewable;
|
||||
|
||||
|
|
Loading…
Reference in New Issue