Commit 0d580356 authored by Raphael Quinet's avatar Raphael Quinet Committed by Raphaël Quinet

Added placeholder for file properties.

2005-03-04  Raphael Quinet  <raphael@gimp.org>

	* menus/image-menu.xml.in: Added placeholder for file properties.

	* plug-ins/metadata/.cvsignore
	* plug-ins/metadata/Makefile.am
	* plug-ins/metadata/README
	* plug-ins/metadata/interface.c
	* plug-ins/metadata/interface.h
	* plug-ins/metadata/metadata.c
	* plug-ins/metadata/xmp-model.c
	* plug-ins/metadata/xmp-model.h
	* plug-ins/metadata/xmp-parse.c
	* plug-ins/metadata/xmp-parse.h
	* plug-ins/metadata/xmp-gen.c
	* plug-ins/metadata/xmp-gen.h: First import of metadata editor.
	Currently, it cannot read metadata (except for XMP), it cannot
	edit metadata and it cannot save metadata (just export).  But this
	might improve later...  The README file contains some info.
parent cc4e204b
2005-03-04 Raphaël Quinet <raphael@gimp.org>
* menus/image-menu.xml.in: Added placeholder for file properties.
* plug-ins/metadata/.cvsignore
* plug-ins/metadata/Makefile.am
* plug-ins/metadata/README
* plug-ins/metadata/interface.c
* plug-ins/metadata/interface.h
* plug-ins/metadata/metadata.c
* plug-ins/metadata/xmp-model.c
* plug-ins/metadata/xmp-model.h
* plug-ins/metadata/xmp-parse.c
* plug-ins/metadata/xmp-parse.h
* plug-ins/metadata/xmp-gen.c
* plug-ins/metadata/xmp-gen.h: First import of metadata editor.
Currently, it cannot read metadata (except for XMP), it cannot
edit metadata and it cannot save metadata (just export). But this
might improve later... The README file contains some info.
2005-03-04 Sven Neumann <sven@gimp.org>
* app/dialogs/user-install-dialog.c
......
......@@ -30,6 +30,8 @@
<separator />
<placeholder name="Send" />
<separator />
<placeholder name="Info" />
<separator />
<menuitem action="view-close" />
<menuitem action="file-quit" />
</menu>
......
Makefile
Makefile.in
.deps
.libs
metadata
xmpdump
## Process this file with automake to produce Makefile.in
libgimpui = $(top_builddir)/libgimp/libgimpui-$(GIMP_API_VERSION).la
libgimpwidgets = $(top_builddir)/libgimpwidgets/libgimpwidgets-$(GIMP_API_VERSION).la
libgimp = $(top_builddir)/libgimp/libgimp-$(GIMP_API_VERSION).la
libgimpcolor = $(top_builddir)/libgimpcolor/libgimpcolor-$(GIMP_API_VERSION).la
libgimpbase = $(top_builddir)/libgimpbase/libgimpbase-$(GIMP_API_VERSION).la
if OS_WIN32
mwindows = -mwindows
endif
AM_LDFLAGS = $(mwindows)
libexecdir = $(gimpplugindir)/plug-ins
libexec_PROGRAMS = metadata
metadata_SOURCES = \
metadata.c \
interface.h \
interface.c \
xmp-model.h \
xmp-model.c \
xmp-parse.h \
xmp-parse.c \
xmp-gen.h \
xmp-gen.c
# exif-parse.h \
# exif-parse.c \
# exif-gen.h \
# exif-gen.c \
# iptc-parse.h \
# iptc-parse.c
noinst_PROGRAMS = xmpdump
xmpdump_SOURCES = \
xmpdump.c \
xmp-parse.h \
xmp-parse.c
INCLUDES = \
-I$(top_srcdir) \
$(GTK_CFLAGS) \
$(EXIF_CFLAGS) \
-I$(includedir)
LDADD = \
$(libgimpui) \
$(libgimpwidgets) \
$(libgimp) \
$(libgimpcolor) \
$(libgimpbase) \
$(GTK_LIBS) \
$(RT_LIBS) \
$(INTLLIBS)
What is this?
-------------
This is the beginning of an editor for metadata. It is far from
complete yet.
Current status
--------------
- It does not read metadata, except if there is an XMP block in the
image file.
- It does not write metadata, it can only export XMP into a separate
file.
- It does not edit metadata, except for some very limited editing of
basic scalar types (strings, integers, ...). It is currently not
possible to add new properties using the editor (but this can be
done via the PDB call plug_in_metadata_set_simple()).
- Basically, the current code is only useful for viewing some XMP
metadata if the image file contains an XMP block. The import/export
functions are also supposed to work. Import merges, so it is
possible for example to import a license file such as the XMP files
from Creative Commons in order to apply a license to an image.
- The metadata is saved in a persistent parasite that is overwritten
after each call. Caution: the editor should not be open while you
are trying to test some of the PDB calls, otherwise you would
discard all changes as soon as you press OK. This is a problem that
cannot be solved easily as long as the metadata editor is a plug-in.
How to find test images?
------------------------
The easiest way is to try a Google search for "<?xpacket". This is
the marker that is used at the beginning of XMP packets. Many images
or PDF files are incorrectly served as text/plain and therefore
indexed by Google as text files. By looking for XMP tags such as
"<?xpacket", it is possible to find a large number of files containing
XMP metadata.
Work in progress:
-----------------
- improve XMP code generation (xmp-gen.c) - currently, some structured
property types are not written back to the buffer, so the round-trip
decode/encode can silently discard some properties
- add tabs for easy editing of metadata, connect them to the tree
- fix the conversion to/from EXIF (exif-parse.c, exif-gen.c)
- register PDB functions correctly (for setting/getting metadata)
- update the JPEG plug-in
Near future:
- add custom callbacks for editing in the tree, validate entries, ...
- smarter display of rational values, closed sets, ...
- improve the layout of the various tabs
Not-so-near future:
- move some of this stuff into the core
-------------------------------------------------------------------------------
Files modified (2004-08-24):
configure.in (added /plug-ins/metadata/Makefile)
menus/image-menu.xml.in (added placeholder "<Image>/File/Info")
plug-ins/Makefile.am (added "metadata" in SUBDIRS)
plug-ins/common/jpeg.c (changed to get/set metadata through PDB)
New files:
plug-ins/metadata/Makefile.am (generates Makefile.in to get a Makefile)
plug-ins/metadata/metadata.c (main part: registers the plug-in, etc.)
plug-ins/metadata/interface.h
plug-ins/metadata/interface.c (user interface: widgets and callbacks)
plug-ins/metadata/xmp-model.h
plug-ins/metadata/xmp-model.c (model for the treeview, list of XMP schemas)
plug-ins/metadata/xmp-parse.h
plug-ins/metadata/xmp-parse.c (simple parser for XMP metadata)
plug-ins/metadata/xmp-gen.h
plug-ins/metadata/xmp-gen.c (generates XMP metadata from the tree model)
plug-ins/metadata/exif-parse.h
plug-ins/metadata/exif-parse.c (converts EXIF into the XMP tree model)
plug-ins/metadata/exif-gen.h
plug-ins/metadata/exif-gen.c (generates EXIF metadata from the tree model)
/* interface.c - user interface for the metadata editor
*
* Copyright (C) 2004-2005, Raphaël Quinet <raphael@gimp.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "config.h"
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <glib.h>
#include <glib/gstdio.h>
#ifdef G_OS_WIN32
#include <io.h>
#endif
#ifndef _O_BINARY
#define _O_BINARY 0
#endif
#include <gtk/gtk.h>
#include <libgimp/gimp.h>
#include <libgimp/gimpui.h>
#include "libgimp/stdplugins-intl.h"
#include "interface.h"
#include "xmp-model.h"
#include "xmp-gen.h"
#define RESPONSE_IMPORT 1
#define RESPONSE_EXPORT 2
typedef struct
{
GtkWidget *dlg;
XMPModel *xmp_model;
GdkPixbuf *edit_icon;
GdkPixbuf *auto_icon;
gboolean run_ok;
} MetadataGui;
static void
value_edited (GtkCellRendererText *cell,
const gchar *path_string,
const gchar *new_text,
gpointer data)
{
GtkTreeModel *model = (GtkTreeModel *)data;
GtkTreePath *path = gtk_tree_path_new_from_string (path_string);
GtkTreeIter iter;
gchar *old_text;
gtk_tree_model_get_iter (model, &iter, path);
gtk_tree_model_get (model, &iter, COL_XMP_VALUE, &old_text, -1);
g_free (old_text);
/* FIXME: update value[] array */
/* FIXME: check widget xref and update other widget if not NULL */
gtk_tree_store_set (GTK_TREE_STORE (model), &iter,
COL_XMP_VALUE, new_text,
-1);
gtk_tree_path_free (path);
}
static void
add_view_columns (GtkTreeView *treeview)
{
gint col_offset;
GtkCellRenderer *renderer;
GtkTreeViewColumn *column;
GtkTreeModel *model = gtk_tree_view_get_model (treeview);
/* Property Name */
renderer = gtk_cell_renderer_text_new ();
g_object_set (renderer, "xalign", 0.0, NULL);
col_offset =
gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview),
-1, _("Property"),
renderer,
"text",
COL_XMP_NAME,
"weight",
COL_XMP_WEIGHT,
"weight-set",
COL_XMP_WEIGHT_SET,
NULL);
column = gtk_tree_view_get_column (GTK_TREE_VIEW (treeview), col_offset - 1);
gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE);
/* Icon */
renderer = gtk_cell_renderer_pixbuf_new ();
col_offset =
gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview),
-1, "",
renderer,
"pixbuf",
COL_XMP_EDIT_ICON,
"visible",
COL_XMP_VISIBLE,
NULL);
column = gtk_tree_view_get_column (GTK_TREE_VIEW (treeview), col_offset - 1);
gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE);
/* Value */
renderer = gtk_cell_renderer_text_new ();
g_object_set (renderer, "xalign", 0.0, NULL);
g_signal_connect (renderer, "edited",
G_CALLBACK (value_edited), model);
col_offset =
gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview),
-1, _("Value"),
renderer,
"text",
COL_XMP_VALUE,
"editable",
COL_XMP_EDITABLE,
"visible",
COL_XMP_VISIBLE,
NULL);
column = gtk_tree_view_get_column (GTK_TREE_VIEW (treeview), col_offset - 1);
gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE);
}
static gboolean
icon_foreach_func (GtkTreeModel *model,
GtkTreePath *path,
GtkTreeIter *iter,
gpointer user_data)
{
gboolean editable;
MetadataGui *mgui = user_data;
gtk_tree_model_get (model, iter,
COL_XMP_EDITABLE, &editable,
-1);
if (editable == XMP_AUTO_UPDATE)
gtk_tree_store_set (GTK_TREE_STORE (model), iter,
COL_XMP_EDIT_ICON, mgui->auto_icon,
-1);
else if (editable == TRUE)
gtk_tree_store_set (GTK_TREE_STORE (model), iter,
COL_XMP_EDIT_ICON, mgui->edit_icon,
-1);
else
gtk_tree_store_set (GTK_TREE_STORE (model), iter,
COL_XMP_EDIT_ICON, NULL,
-1);
return FALSE;
}
static void
update_icons (MetadataGui *mgui)
{
GtkTreeModel *model;
/* add the edit icon to the rows that are editable */
model = xmp_model_get_tree_model (mgui->xmp_model);
gtk_tree_model_foreach (model, icon_foreach_func, mgui);
}
static void
add_description_tab (GtkWidget *notebook)
{
GtkWidget *frame;
GtkWidget *table;
GtkWidget *entry;
GtkWidget *scrolled_window;
GtkWidget *text_view;
GtkTextBuffer *text_buffer;
frame = gimp_frame_new (_("Description"));
gtk_notebook_append_page (GTK_NOTEBOOK (notebook), frame,
gtk_label_new (_("Description")));
gtk_container_set_border_width (GTK_CONTAINER (frame), 10);
/* gtk_widget_show (frame); */
table = gtk_table_new (5, 2, FALSE);
gtk_table_set_col_spacings (GTK_TABLE (table), 6);
gtk_table_set_row_spacings (GTK_TABLE (table), 6);
gtk_container_add (GTK_CONTAINER (frame), table);
/* gtk_widget_show (table); */
entry = gtk_entry_new ();
gimp_table_attach_aligned (GTK_TABLE (table), 0, 0,
_("Image _Title:"), 0.0, 0.5,
entry, 1, FALSE);
entry = gtk_entry_new ();
gimp_table_attach_aligned (GTK_TABLE (table), 0, 1,
_("_Author:"), 0.0, 0.5,
entry, 1, FALSE);
scrolled_window = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window),
GTK_SHADOW_IN);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
GTK_POLICY_AUTOMATIC,
GTK_POLICY_AUTOMATIC);
text_view = gtk_text_view_new ();
text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text_view));
gtk_text_buffer_set_text (text_buffer, "FIXME:\nThese widgets are currently disconnected from the XMP model.\nPlease use the Advanced tab.", -1); /*FIXME*/
gtk_container_add (GTK_CONTAINER (scrolled_window), text_view);
gimp_table_attach_aligned (GTK_TABLE (table), 0, 2,
_("_Description:"), 0.0, 0.5,
scrolled_window, 1, FALSE);
entry = gtk_entry_new ();
gimp_table_attach_aligned (GTK_TABLE (table), 0, 3,
_("Description _Writer:"), 0.0, 0.5,
entry, 1, FALSE);
scrolled_window = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window),
GTK_SHADOW_IN);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
GTK_POLICY_AUTOMATIC,
GTK_POLICY_AUTOMATIC);
text_view = gtk_text_view_new ();
text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text_view));
gtk_container_add (GTK_CONTAINER (scrolled_window), text_view);
gimp_table_attach_aligned (GTK_TABLE (table), 0, 4,
_("_Keywords:"), 0.0, 0.5,
scrolled_window, 1, FALSE);
gtk_widget_show_all (frame);
}
static void
add_copyright_tab (GtkWidget *notebook)
{
GtkWidget *label;
label = gtk_label_new (_("Empty"));
gtk_notebook_append_page (GTK_NOTEBOOK (notebook), label,
gtk_label_new (_("Copyright")));
gtk_widget_show (label);
}
static void
add_origin_tab (GtkWidget *notebook)
{
GtkWidget *label;
label = gtk_label_new (_("Empty"));
gtk_notebook_append_page (GTK_NOTEBOOK (notebook), label,
gtk_label_new (_("Origin")));
gtk_widget_show (label);
}
static void
add_camera1_tab (GtkWidget *notebook)
{
GtkWidget *label;
label = gtk_label_new (_("Empty"));
gtk_notebook_append_page (GTK_NOTEBOOK (notebook), label,
gtk_label_new (_("Camera 1")));
gtk_widget_show (label);
}
static void
add_camera2_tab (GtkWidget *notebook)
{
GtkWidget *label;
label = gtk_label_new (_("Empty"));
gtk_notebook_append_page (GTK_NOTEBOOK (notebook), label,
gtk_label_new (_("Camera 2")));
gtk_widget_show (label);
}
static void
add_advanced_tab (GtkWidget *notebook,
GtkTreeModel *model)
{
GtkWidget *sw;
GtkWidget *treeview;
/* Advanced tab */
sw = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
GTK_SHADOW_ETCHED_IN);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
GTK_POLICY_AUTOMATIC,
GTK_POLICY_AUTOMATIC);
gtk_notebook_append_page (GTK_NOTEBOOK (notebook), sw,
gtk_label_new (_("Advanced")));
/* create tree view - model will be unref'ed in xmp_model_free() */
treeview = gtk_tree_view_new_with_model (model);
gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (treeview), TRUE);
add_view_columns (GTK_TREE_VIEW (treeview));
gtk_container_add (GTK_CONTAINER (sw), treeview);
/* expand all rows after the treeview widget has been realized */
g_signal_connect (treeview, "realize",
G_CALLBACK (gtk_tree_view_expand_all), NULL);
gtk_widget_show (treeview);
gtk_widget_show (sw);
}
/* show a transient message dialog */
static void
metadata_message_dialog (GtkMessageType type,
GtkWindow *parent,
const gchar *title,
const gchar *message)
{
GtkWidget *dlg;
dlg = gtk_message_dialog_new (parent, 0, type, GTK_BUTTONS_OK, message);
if (title)
gtk_window_set_title (GTK_WINDOW (dlg), title);
gtk_window_set_role (GTK_WINDOW (dlg), "metadata-message");
gtk_dialog_run (GTK_DIALOG (dlg));
gtk_widget_destroy (dlg);
}
/* load XMP metadata from a file (the file may contain other data) */
static void
import_dialog_response (GtkWidget *dlg,
gint response_id,
gpointer data)
{
MetadataGui *mgui = data;
g_return_if_fail (mgui != NULL);
if (response_id == GTK_RESPONSE_OK)
{
gchar *filename;
gchar *buffer;
guint buffer_length;
GError *error = NULL;
filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dlg));
if (! g_file_get_contents (filename, &buffer, &buffer_length, &error))
{
metadata_message_dialog (GTK_MESSAGE_ERROR, GTK_WINDOW (dlg),
_("Open failed"), error->message);
g_error_free (error);
g_free (filename);
return;
}
if (! xmp_model_parse_buffer (mgui->xmp_model, buffer, buffer_length,
TRUE, &error))
{
metadata_message_dialog (GTK_MESSAGE_ERROR, GTK_WINDOW (dlg),
_("Open failed"), error->message);
g_error_free (error);
g_free (filename);
return;
}
update_icons (mgui);
g_free (buffer);
g_free (filename);
}
gtk_widget_destroy (dlg); /* FIXME: destroy or unmap? */
}
/* select file to import */
static void
file_import_dialog (GtkWidget *parent,
MetadataGui *mgui)
{
static GtkWidget *dlg = NULL;
if (! dlg)
{
dlg =
gtk_file_chooser_dialog_new (_("Import XMP from file"),
GTK_WINDOW (parent),
GTK_FILE_CHOOSER_ACTION_OPEN,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_OPEN, GTK_RESPONSE_OK,
NULL);
/* FIXME: gimp_help_connect? */
gtk_dialog_set_default_response (GTK_DIALOG (dlg), GTK_RESPONSE_OK);
g_signal_connect (dlg, "destroy",
G_CALLBACK (gtk_widget_destroyed),
&dlg);
g_signal_connect (dlg, "response",
G_CALLBACK (import_dialog_response),
mgui);
}
gtk_window_present (GTK_WINDOW (dlg));
}
/* save XMP metadata to a file (only XMP, nothing else) */
static void
export_dialog_response (GtkWidget *dlg,
gint response_id,
gpointer data)
{
MetadataGui *mgui = data;
g_return_if_fail (mgui != NULL);
if (response_id == GTK_RESPONSE_OK)
{
gchar *filename;
gchar *buffer;
guint buffer_length;
int fd;
filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dlg));
/* FIXME: improve this code and rewrite the error handling */
buffer_length = xmp_estimate_size (mgui->xmp_model);
buffer = g_new (gchar, buffer_length);
xmp_generate_block (mgui->xmp_model, buffer, buffer_length);
fd = g_open (filename, O_CREAT | O_TRUNC | O_WRONLY | _O_BINARY, 0666);
if (fd < 0)
{
metadata_message_dialog (GTK_MESSAGE_ERROR, GTK_WINDOW (dlg),
_("Open failed"),
_("Cannot create file"));
g_free (buffer);
g_free (filename);
return;
}
fprintf (stderr, "\nwriting %d bytes to %s...\n", strlen(buffer), filename);
if (write (fd, buffer, strlen (buffer)) < 0)
{
metadata_message_dialog (GTK_MESSAGE_ERROR, GTK_WINDOW (dlg),
_("Save failed"),
_("Some error occured while saving"));
g_free (buffer);
g_free (filename);
return;
}
if (close (fd) < 0)
{
metadata_message_dialog (GTK_MESSAGE_ERROR, GTK_WINDOW (dlg),
_("Save failed"),
_("Could not close the file"));
g_free (buffer);
g_free (filename);
return;
}
g_free (buffer);
g_free (filename);
}
gtk_widget_destroy (dlg); /* FIXME: destroy or unmap? */
}
/* select file to export */
static void
file_export_dialog (GtkWidget *parent,
MetadataGui *mgui)
{
static GtkWidget *dlg = NULL;
if (! dlg)
{
dlg =
gtk_file_chooser_dialog_new (_("Export XMP to file"),
GTK_WINDOW (parent),
GTK_FILE_CHOOSER_ACTION_SAVE,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_OPEN, GTK_RESPONSE_OK,
NULL);
/* FIXME: gimp_help_connect? */
gtk_dialog_set_default_response (GTK_DIALOG (dlg), GTK_RESPONSE_OK);
g_signal_connect (dlg, "destroy",
G_CALLBACK (gtk_widget_destroyed),
&dlg);
g_signal_connect (dlg, "response",
G_CALLBACK (export_dialog_response),
mgui);
}
gtk_window_present (GTK_WINDOW (dlg));
}
static void
metadata_dialog_response (GtkWidget *widget,
gint response_id,
gpointer data)
{
MetadataGui *mgui = data;
g_return_if_fail (mgui != NULL);
switch (response_id)
{
case RESPONSE_IMPORT:
file_import_dialog (widget, mgui);
break;
case RESPONSE_EXPORT:
file_export_dialog (widget, mgui);
break;
case GTK_RESPONSE_OK:
mgui->run_ok = TRUE;
/*fallthrough*/
default:
gtk_widget_destroy (widget);
break;
}
}
gboolean
metadata_dialog (gint32 image_ID,
XMPModel *xmp_model)
{
MetadataGui mgui;
GtkWidget *notebook;
gimp_ui_init ("metadata", FALSE);
mgui.dlg = gimp_dialog_new (_("Image Properties"), "metadata",
NULL, 0,
gimp_standard_help_func, "plug-in-metadata",
_("_Import XMP"), RESPONSE_IMPORT,
_("_Export XMP"), RESPONSE_EXPORT,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_OK, GTK_RESPONSE_OK,
NULL);
g_signal_connect (mgui.dlg, "response",
G_CALLBACK (metadata_dialog_response),