Commit b81b6095 authored by Michael Natterer's avatar Michael Natterer 😴

app: bring the "Switches" column to the channel and path properties dialogs

Introduce item-options-dialog.[ch] which abstracts this away and use
it from the layer, channel, vectors options dialogs. This is all
pretty ugly but better than duplicating that code three times. The
vector-options-dialog is now completely pointless but I kept it anyway
for now, let's see what unique path options we come up with.
parent f4a059b8
......@@ -62,6 +62,10 @@ static void channels_new_callback (GtkWidget *dialog,
const gchar *channel_name,
const GimpRGB *channel_color,
gboolean save_selection,
gboolean channel_visible,
gboolean channel_linked,
gboolean channel_lock_content,
gboolean channel_lock_position,
gpointer user_data);
static void channels_edit_attributes_callback (GtkWidget *dialog,
GimpImage *image,
......@@ -70,6 +74,10 @@ static void channels_edit_attributes_callback (GtkWidget *dialog,
const gchar *channel_name,
const GimpRGB *channel_color,
gboolean save_selection,
gboolean channel_visible,
gboolean channel_linked,
gboolean channel_lock_content,
gboolean channel_lock_position,
gpointer user_data);
......@@ -92,6 +100,8 @@ channels_edit_attributes_cmd_callback (GtkAction *action,
if (! dialog)
{
GimpItem *item = GIMP_ITEM (channel);
dialog = channel_options_dialog_new (image, channel,
action_data_get_context (data),
widget,
......@@ -100,11 +110,15 @@ channels_edit_attributes_cmd_callback (GtkAction *action,
"gtk-edit",
_("Edit Channel Attributes"),
GIMP_HELP_CHANNEL_EDIT,
gimp_object_get_name (channel),
&channel->color,
_("Edit Channel Color"),
_("_Fill opacity"),
_("_Fill opacity:"),
FALSE,
gimp_object_get_name (channel),
&channel->color,
gimp_item_get_visible (item),
gimp_item_get_linked (item),
gimp_item_get_lock_content (item),
gimp_item_get_lock_position (item),
channels_edit_attributes_callback,
NULL);
......@@ -140,11 +154,15 @@ channels_new_cmd_callback (GtkAction *action,
GIMP_STOCK_CHANNEL,
_("Create a New Channel"),
GIMP_HELP_CHANNEL_NEW,
_("New Channel Color"),
_("_Fill opacity:"),
TRUE,
config->channel_new_name,
&config->channel_new_color,
_("New Channel Color"),
_("_Fill opacity"),
TRUE,
FALSE,
FALSE,
FALSE,
channels_new_callback,
NULL);
......@@ -355,6 +373,10 @@ channels_new_callback (GtkWidget *dialog,
const gchar *channel_name,
const GimpRGB *channel_color,
gboolean save_selection,
gboolean channel_visible,
gboolean channel_linked,
gboolean channel_lock_content,
gboolean channel_lock_position,
gpointer user_data)
{
GimpDialogConfig *config = GIMP_DIALOG_CONFIG (image->gimp->config);
......@@ -387,6 +409,11 @@ channels_new_callback (GtkWidget *dialog,
GIMP_FILL_TRANSPARENT);
}
gimp_item_set_visible (GIMP_ITEM (channel), channel_visible, FALSE);
gimp_item_set_linked (GIMP_ITEM (channel), channel_linked, FALSE);
gimp_item_set_lock_content (GIMP_ITEM (channel), channel_lock_content, FALSE);
gimp_item_set_lock_position (GIMP_ITEM (channel), channel_lock_position, FALSE);
gimp_image_add_channel (image, channel,
GIMP_IMAGE_ACTIVE_PARENT, -1, TRUE);
gimp_image_flush (image);
......@@ -402,32 +429,44 @@ channels_edit_attributes_callback (GtkWidget *dialog,
const gchar *channel_name,
const GimpRGB *channel_color,
gboolean save_selection,
gboolean channel_visible,
gboolean channel_linked,
gboolean channel_lock_content,
gboolean channel_lock_position,
gpointer user_data)
{
gboolean name_changed = FALSE;
gboolean color_changed = FALSE;
if (strcmp (channel_name, gimp_object_get_name (channel)))
name_changed = TRUE;
if (gimp_rgba_distance (channel_color, &channel->color) > 0.0001)
color_changed = TRUE;
if (name_changed || color_changed)
GimpItem *item = GIMP_ITEM (channel);
if (strcmp (channel_name, gimp_object_get_name (channel)) ||
gimp_rgba_distance (channel_color, &channel->color) > 0.0001 ||
channel_visible != gimp_item_get_visible (item) ||
channel_linked != gimp_item_get_linked (item) ||
channel_lock_content != gimp_item_get_lock_content (item) ||
channel_lock_position != gimp_item_get_lock_position (item))
{
if (name_changed && color_changed)
gimp_image_undo_group_start (image,
GIMP_UNDO_GROUP_ITEM_PROPERTIES,
_("Channel Attributes"));
gimp_image_undo_group_start (image,
GIMP_UNDO_GROUP_ITEM_PROPERTIES,
_("Channel Attributes"));
if (name_changed)
if (strcmp (channel_name, gimp_object_get_name (channel)))
gimp_item_rename (GIMP_ITEM (channel), channel_name, NULL);
if (color_changed)
if (gimp_rgba_distance (channel_color, &channel->color) > 0.0001)
gimp_channel_set_color (channel, channel_color, TRUE);
if (name_changed && color_changed)
gimp_image_undo_group_end (image);
if (channel_visible != gimp_item_get_visible (item))
gimp_item_set_visible (item, channel_visible, TRUE);
if (channel_linked != gimp_item_get_linked (item))
gimp_item_set_linked (item, channel_linked, TRUE);
if (channel_lock_content != gimp_item_get_lock_content (item))
gimp_item_set_lock_content (item, channel_lock_content, TRUE);
if (channel_lock_position != gimp_item_get_lock_position (item))
gimp_item_set_lock_position (item, channel_lock_position, TRUE);
gimp_image_undo_group_end (image);
gimp_image_flush (image);
}
......
......@@ -243,6 +243,8 @@ layers_edit_attributes_cmd_callback (GtkAction *action,
if (! dialog)
{
GimpItem *item = GIMP_ITEM (layer);
dialog = layer_options_dialog_new (gimp_item_get_image (GIMP_ITEM (layer)),
layer,
action_data_get_context (data),
......@@ -256,6 +258,11 @@ layers_edit_attributes_cmd_callback (GtkAction *action,
gimp_layer_get_mode (layer),
gimp_layer_get_opacity (layer),
0 /* unused */,
gimp_item_get_visible (item),
gimp_item_get_linked (item),
gimp_item_get_lock_content (item),
gimp_item_get_lock_position (item),
gimp_layer_get_lock_alpha (layer),
layers_edit_attributes_callback,
NULL);
......@@ -316,6 +323,11 @@ layers_new_cmd_callback (GtkAction *action,
config->layer_new_mode,
config->layer_new_opacity,
config->layer_new_fill_type,
TRUE,
FALSE,
FALSE,
FALSE,
FALSE,
layers_new_callback,
NULL);
......
......@@ -34,6 +34,7 @@
#include "dialogs/dialogs.h"
#include "dialogs/channel-options-dialog.h"
#include "dialogs/item-options-dialog.h"
#include "actions.h"
#include "quick-mask-commands.h"
......@@ -50,6 +51,10 @@ static void quick_mask_configure_callback (GtkWidget *dialog,
const gchar *channel_name,
const GimpRGB *channel_color,
gboolean save_selection,
gboolean channel_visible,
gboolean channel_linked,
gboolean channel_lock_content,
gboolean channel_lock_position,
gpointer user_data);
......@@ -118,14 +123,20 @@ quick_mask_configure_cmd_callback (GtkAction *action,
GIMP_STOCK_QUICK_MASK_ON,
_("Edit Quick Mask Attributes"),
GIMP_HELP_QUICK_MASK_EDIT,
_("Edit Quick Mask Color"),
_("_Mask opacity:"),
FALSE,
NULL,
&color,
_("Edit Quick Mask Color"),
_("_Mask opacity"),
FALSE,
FALSE,
FALSE,
FALSE,
quick_mask_configure_callback,
NULL);
item_options_dialog_set_switches_visible (dialog, FALSE);
dialogs_attach_dialog (G_OBJECT (image), CONFIGURE_DIALOG_KEY, dialog);
}
......@@ -143,6 +154,10 @@ quick_mask_configure_callback (GtkWidget *dialog,
const gchar *channel_name,
const GimpRGB *channel_color,
gboolean save_selection,
gboolean channel_visible,
gboolean channel_linked,
gboolean channel_lock_content,
gboolean channel_lock_position,
gpointer user_data)
{
GimpRGB old_color;
......
......@@ -77,12 +77,22 @@
static void vectors_new_callback (GtkWidget *dialog,
GimpImage *image,
GimpVectors *vectors,
GimpContext *context,
const gchar *vectors_name,
gboolean vectors_visible,
gboolean vectors_linked,
gboolean vectors_lock_content,
gboolean vectors_lock_position,
gpointer user_data);
static void vectors_edit_attributes_callback (GtkWidget *dialog,
GimpImage *image,
GimpVectors *vectors,
GimpContext *context,
const gchar *vectors_name,
gboolean vectors_visible,
gboolean vectors_linked,
gboolean vectors_lock_content,
gboolean vectors_lock_position,
gpointer user_data);
static void vectors_fill_callback (GtkWidget *dialog,
GimpItem *item,
......@@ -150,6 +160,8 @@ vectors_edit_attributes_cmd_callback (GtkAction *action,
if (! dialog)
{
GimpItem *item = GIMP_ITEM (vectors);
dialog = vectors_options_dialog_new (image, vectors,
action_data_get_context (data),
widget,
......@@ -159,6 +171,10 @@ vectors_edit_attributes_cmd_callback (GtkAction *action,
_("Edit Path Attributes"),
GIMP_HELP_PATH_EDIT,
gimp_object_get_name (vectors),
gimp_item_get_visible (item),
gimp_item_get_linked (item),
gimp_item_get_lock_content (item),
gimp_item_get_lock_position (item),
vectors_edit_attributes_callback,
NULL);
......@@ -195,6 +211,10 @@ vectors_new_cmd_callback (GtkAction *action,
_("Create a New Path"),
GIMP_HELP_PATH_NEW,
config->vectors_new_name,
FALSE,
FALSE,
FALSE,
FALSE,
vectors_new_callback,
NULL);
......@@ -816,7 +836,12 @@ static void
vectors_new_callback (GtkWidget *dialog,
GimpImage *image,
GimpVectors *vectors,
GimpContext *context,
const gchar *vectors_name,
gboolean vectors_visible,
gboolean vectors_linked,
gboolean vectors_lock_content,
gboolean vectors_lock_position,
gpointer user_data)
{
GimpDialogConfig *config = GIMP_DIALOG_CONFIG (image->gimp->config);
......@@ -826,6 +851,11 @@ vectors_new_callback (GtkWidget *dialog,
NULL);
vectors = gimp_vectors_new (image, config->vectors_new_name);
gimp_item_set_visible (GIMP_ITEM (vectors), vectors_visible, FALSE);
gimp_item_set_linked (GIMP_ITEM (vectors), vectors_linked, FALSE);
gimp_item_set_lock_content (GIMP_ITEM (vectors), vectors_lock_content, FALSE);
gimp_item_set_lock_position (GIMP_ITEM (vectors), vectors_lock_position, FALSE);
gimp_image_add_vectors (image, vectors,
GIMP_IMAGE_ACTIVE_PARENT, -1, TRUE);
gimp_image_flush (image);
......@@ -837,12 +867,43 @@ static void
vectors_edit_attributes_callback (GtkWidget *dialog,
GimpImage *image,
GimpVectors *vectors,
GimpContext *context,
const gchar *vectors_name,
gboolean vectors_visible,
gboolean vectors_linked,
gboolean vectors_lock_content,
gboolean vectors_lock_position,
gpointer user_data)
{
if (strcmp (vectors_name, gimp_object_get_name (vectors)))
GimpItem *item = GIMP_ITEM (vectors);
if (strcmp (vectors_name, gimp_object_get_name (vectors)) ||
vectors_visible != gimp_item_get_visible (item) ||
vectors_linked != gimp_item_get_linked (item) ||
vectors_lock_content != gimp_item_get_lock_content (item) ||
vectors_lock_position != gimp_item_get_lock_position (item))
{
gimp_item_rename (GIMP_ITEM (vectors), vectors_name, NULL);
gimp_image_undo_group_start (image,
GIMP_UNDO_GROUP_ITEM_PROPERTIES,
_("Path Attributes"));
if (strcmp (vectors_name, gimp_object_get_name (vectors)))
gimp_item_rename (GIMP_ITEM (vectors), vectors_name, NULL);
if (vectors_visible != gimp_item_get_visible (item))
gimp_item_set_visible (item, vectors_visible, TRUE);
if (vectors_linked != gimp_item_get_linked (item))
gimp_item_set_linked (item, vectors_linked, TRUE);
if (vectors_lock_content != gimp_item_get_lock_content (item))
gimp_item_set_lock_content (item, vectors_lock_content, TRUE);
if (vectors_lock_position != gimp_item_get_lock_position (item))
gimp_item_set_lock_position (item, vectors_lock_position, TRUE);
gimp_image_undo_group_end (image);
gimp_image_flush (image);
}
......
......@@ -57,6 +57,8 @@ libappdialogs_a_sources = \
image-scale-dialog.h \
input-devices-dialog.c \
input-devices-dialog.h \
item-options-dialog.c \
item-options-dialog.h \
keyboard-shortcuts-dialog.c \
keyboard-shortcuts-dialog.h \
layer-add-mask-dialog.c \
......
......@@ -34,6 +34,7 @@
#include "widgets/gimpviewabledialog.h"
#include "channel-options-dialog.h"
#include "item-options-dialog.h"
#include "gimp-intl.h"
......@@ -42,28 +43,31 @@ typedef struct _ChannelOptionsDialog ChannelOptionsDialog;
struct _ChannelOptionsDialog
{
GimpImage *image;
GimpContext *context;
GimpChannel *channel;
GimpChannelOptionsCallback callback;
gpointer user_data;
GtkWidget *name_entry;
GtkWidget *color_panel;
GtkWidget *save_sel_checkbutton;
GtkWidget *save_sel_toggle;
};
/* local function prototypes */
static void channel_options_dialog_response (GtkWidget *dialog,
gint response_id,
ChannelOptionsDialog *private);
static void channel_options_opacity_update (GtkAdjustment *adjustment,
static void channel_options_dialog_free (ChannelOptionsDialog *private);
static void channel_options_dialog_callback (GtkWidget *dialog,
GimpImage *image,
GimpItem *item,
GimpContext *context,
const gchar *item_name,
gboolean item_visible,
gboolean item_linked,
gboolean item_lock_content,
gboolean item_lock_position,
gpointer user_data);
static void channel_options_opacity_changed (GtkAdjustment *adjustment,
GimpColorButton *color_button);
static void channel_options_color_changed (GimpColorButton *color_button,
GtkAdjustment *adjustment);
static void channel_options_dialog_free (ChannelOptionsDialog *private);
/* public functions */
......@@ -78,19 +82,20 @@ channel_options_dialog_new (GimpImage *image,
const gchar *icon_name,
const gchar *desc,
const gchar *help_id,
const gchar *channel_name,
const GimpRGB *channel_color,
const gchar *color_label,
const gchar *opacity_label,
gboolean show_from_sel,
const gchar *channel_name,
const GimpRGB *channel_color,
gboolean channel_visible,
gboolean channel_linked,
gboolean channel_lock_content,
gboolean channel_lock_position,
GimpChannelOptionsCallback callback,
gpointer user_data)
{
ChannelOptionsDialog *private;
GtkWidget *dialog;
GimpViewable *viewable;
GtkWidget *hbox;
GtkWidget *vbox;
GtkAdjustment *opacity_adj;
GtkWidget *scale;
......@@ -110,108 +115,60 @@ channel_options_dialog_new (GimpImage *image,
private = g_slice_new0 (ChannelOptionsDialog);
private->image = image;
private->channel = channel;
private->context = context;
private->callback = callback;
private->user_data = user_data;
if (channel)
viewable = GIMP_VIEWABLE (channel);
else
viewable = GIMP_VIEWABLE (image);
dialog = gimp_viewable_dialog_new (viewable, context,
title, role, icon_name, desc,
parent,
gimp_standard_help_func, help_id,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_OK, GTK_RESPONSE_OK,
NULL);
gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
GTK_RESPONSE_OK,
GTK_RESPONSE_CANCEL,
-1);
dialog = item_options_dialog_new (image, GIMP_ITEM (channel), context,
parent, title, role,
icon_name, desc, help_id,
channel_name ? _("Channel _name:") : NULL,
GIMP_STOCK_TOOL_PAINTBRUSH,
_("Lock _pixels"),
_("Lock position and _size"),
channel_name,
channel_visible,
channel_linked,
channel_lock_content,
channel_lock_position,
channel_options_dialog_callback,
private);
g_object_weak_ref (G_OBJECT (dialog),
(GWeakNotify) channel_options_dialog_free, private);
g_signal_connect (dialog, "response",
G_CALLBACK (channel_options_dialog_response),
private);
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
gtk_container_set_border_width (GTK_CONTAINER (hbox), 12);
gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
hbox, TRUE, TRUE, 0);
gtk_widget_show (hbox);
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0);
gtk_widget_show (vbox);
if (channel_name)
{
GtkWidget *vbox2;
GtkWidget *label;
vbox2 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
gtk_box_pack_start (GTK_BOX (vbox), vbox2, FALSE, FALSE, 0);
gtk_widget_show (vbox2);
label = gtk_label_new_with_mnemonic (_("Channel _name:"));
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
gtk_box_pack_start (GTK_BOX (vbox2), label, FALSE, FALSE, 0);
gtk_widget_show (label);
private->name_entry = gtk_entry_new ();
gtk_entry_set_text (GTK_ENTRY (private->name_entry), channel_name);
gtk_entry_set_activates_default (GTK_ENTRY (private->name_entry), TRUE);
gtk_box_pack_start (GTK_BOX (vbox2), private->name_entry,
FALSE, FALSE, 0);
gtk_widget_show (private->name_entry);
gtk_label_set_mnemonic_widget (GTK_LABEL (label), private->name_entry);
}
opacity_adj = (GtkAdjustment *)
gtk_adjustment_new (channel_color->a * 100.0,
0.0, 100.0, 1.0, 10.0, 0);
scale = gimp_spin_scale_new (opacity_adj, opacity_label, 1);
scale = gimp_spin_scale_new (opacity_adj, NULL, 1);
gtk_widget_set_size_request (scale, 200, -1);
gtk_box_pack_start (GTK_BOX (vbox), scale, FALSE, FALSE, 0);
gtk_widget_show (scale);
item_options_dialog_add_widget (dialog,
opacity_label, scale);
private->color_panel = gimp_color_panel_new (color_label,
channel_color,
GIMP_COLOR_AREA_LARGE_CHECKS,
48, 48);
24, 24);
gimp_color_panel_set_context (GIMP_COLOR_PANEL (private->color_panel),
context);
g_signal_connect (opacity_adj, "value-changed",
G_CALLBACK (channel_options_opacity_update),
G_CALLBACK (channel_options_opacity_changed),
private->color_panel);
gtk_box_pack_start (GTK_BOX (hbox), private->color_panel,
FALSE, FALSE, 0);
gtk_widget_show (private->color_panel);
g_signal_connect (private->color_panel, "color-changed",
G_CALLBACK (channel_options_color_changed),
opacity_adj);
item_options_dialog_add_widget (dialog,
NULL, private->color_panel);
if (show_from_sel)
{
private->save_sel_checkbutton =
private->save_sel_toggle =
gtk_check_button_new_with_mnemonic (_("Initialize from _selection"));
gtk_box_pack_start (GTK_BOX (vbox), private->save_sel_checkbutton,
FALSE, FALSE, 0);
gtk_widget_show (private->save_sel_checkbutton);
item_options_dialog_add_widget (dialog,
NULL, private->save_sel_toggle);
}
return dialog;
......@@ -221,46 +178,53 @@ channel_options_dialog_new (GimpImage *image,
/* private functions */
static void
channel_options_dialog_response (GtkWidget *dialog,
gint response_id,
ChannelOptionsDialog *private)
channel_options_dialog_free (ChannelOptionsDialog *private)
{
if (response_id == GTK_RESPONSE_OK)
{
const gchar *name = NULL;
GimpRGB color;
gboolean save_selection = FALSE;
if (private->name_entry)
name = gtk_entry_get_text (GTK_ENTRY (private->name_entry));
gimp_color_button_get_color (GIMP_COLOR_BUTTON (private->color_panel),
&color);
if (private->save_sel_checkbutton)
save_selection =
gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (private->save_sel_checkbutton));
private->callback (dialog,
private->image,
private->channel,
private->context,
name,
&color,
save_selection,
private->user_data);
}
else
{
gtk_widget_destroy (dialog);
}
g_slice_free (ChannelOptionsDialog, private);
}
static void
channel_options_opacity_update (GtkAdjustment *adjustment,
GimpColorButton *color_button)
channel_options_dialog_callback (GtkWidget *dialog,
GimpImage *image,
GimpItem *item,
GimpContext *context,
const gchar *item_name,
gboolean item_visible,
gboolean item_linked,
gboolean item_lock_content,
gboolean item_lock_position,
gpointer user_data)
{
GimpRGB color;
ChannelOptionsDialog *private = user_data;
GimpRGB color;
gboolean save_selection = FALSE;
gimp_color_button_get_color (GIMP_COLOR_BUTTON (private->color_panel),
&color);
if (private->save_sel_toggle)
save_selection =
gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (private->save_sel_toggle));
private->callback (dialog,
image,
GIMP_CHANNEL (item),
context,
item_name,
&color,
save_selection,
item_visible,
item_linked,
item_lock_content,
item_lock_position,
private->user_data);
}
static void
channel_options_opacity_changed (GtkAdjustment *adjustment,
GimpColorButton *color_button)
{
GimpRGB color;
gimp_color_button_get_color (color_button, &color);
gimp_rgb_set_alpha (&color, gtk_adjustment_get_value (adjustment) / 100.0);
......@@ -271,14 +235,8 @@ static void
channel_options_color_changed (GimpColorButton *button,
GtkAdjustment *adjustment)
{
GimpRGB color;
GimpRGB color;
gimp_color_button_get_color (button, &color);
gtk_adjustment_set_value (adjustment, color.a * 100.0);
}
static void
channel_options_dialog_free (ChannelOptionsDialog *options)
{
g_slice_free (ChannelOptionsDialog, options);
}
......@@ -26,6 +26,10 @@ typedef void (* GimpChannelOptionsCallback) (GtkWidget *dialog,
const gchar *channel_name,
const GimpRGB *channel_color,
gboolean save_selection,
gboolean channel_visible,
gboolean channel_linked,
gboolean channel_lock_content,
gboolean channel_lock_position,
gpointer user_data);
......@@ -38,11 +42,15 @@ GtkWidget * channel_options_dialog_new (GimpImage *image,
const gchar *icon_name,
const gchar *desc,
const gchar *help_id,
const gchar *channel_name,
const GimpRGB *channel_color,
const gchar *color_label,
const gchar *opacity_label,
gboolean show_from_sel,
const gchar *channel_name,
const GimpRGB *channel_color,
gboolean channel_visible,
gboolean channel_linked,
gboolean channel_lock_content,
gboolean channel_lock_position,
GimpChannelOptionsCallback callback,
gpointer user_data);
......
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* 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/>.