cmd manager transactions
- From: Lee Baylis <lee leebaylis co uk>
- To: planner-dev-list gnome org
- Subject: cmd manager transactions
- Date: Sun, 30 Nov 2008 23:22:25 +0000
Lee Baylis wrote:
I have so far enumerated those actions which are capable of moving in
time tasks which are already allocated to a resource. Whenever this
movement can occur relative to other allocated tasks, resource
overallocation is possible. Please let me know if you think I have
missed any:
1) Changing a resource's calendar
There wasn't actually a PlannerCmd in place to handle this, so I have
added one. I haven't attached the patch for this yet though, for reasons
given at the bottom of this mail.
2) Changing project calendars (assuming different resources are using
different calendars)
3) Altering project start date (under same assumption as above)
3) tripped me up a bit as it can be done in two places - via a calendar
pop up or by hand in a text box
4) Indenting a task into a parent
5) Un-indenting a task from a parent
6) Deleting a task and associated tree
7) Changing the maximum number of units associatable with a resource
(currently not implemented in the UI)
8) Assigning a task to a resource
9) Removing a resource assignment
10) Changing the number of units of an assignment
11) Adding a relation to a task via the dialog or dragging between tasks
12) Changing the relation associated with a task
13) Removing a relation from a task
11 and 13 are also possible via the link and unlink buttons and the
unlink right-click popup menu entry, which I had missed.
14) Altering the work of a task via the dialog or clicking on the task
15) Altering the duration of a fixed task
16) Constraining a task
I had also missed:
17) Toggling a task between being a milestone and a normal task.
18) Inserting the first child of a parent as a subtask via the
right-click pop-up menu (as it immediately discards the duration of the
parent and replaces it with the duration of the child).
- the planner cmd manager already seems equipped to handle reversing
actions as a consequence of providing edit->undo
- I found the start of an attempt at cmd transaction support in the
cmd manager code, although it has not yet been completed to the point
where it deals with custom errors mid-transaction
Having made these observations, I am now inclined to change tactic and
try and use the planner cmd manager (probably via transaction support)
to perform actions, check for overload, and then roll them back or
reapply them specifying a different overallocation behaviour. I
wondered if anyone can see any issues with this approach, or has any
other ideas.
I am now convinced that transaction support is the best approach to take
after having finished support for failed transactions and put it into
practice. Patches and a changelog entry for my proposed changes to
transaction support are attached.
If transaction support were the way to go, since it is unfinished, I
can see a few ways to finish it:
i) Halting as soon as an error is encountered, rolling back to the
start of the transaction, and then freeing the cmds in the transaction
so that nothing appears in the redo menu
ii) Entering the end_transaction marker when an error is encountered,
then rolling back actions to the start of the transaction - in this
case, the transaction does appear in the redo menu, but presumably
fails again if someone clicks it and can be configured to roll back
again on redo error
iii) Ignoring the error, carrying on with the transaction, naturally
writing the end_transaction marker, and then evaluating whether there
was an error and rolling back if there was. This method would probably
be better if we had any expectation that the error mid-transaction was
temporary and that the transaction might succeed on redo.
In the end, I opted for an approach which was closest to option 3:
- existing code which makes use of the old transaction functionality
would break if I tried to do 1 or 2, as it relies on writing the end
transaction marker
- my approach handles all my worries about introducing the possibility
for cmd undos to misbehave, by removing the need to introduce a
requirement for cmds which currently cannot return fail to do so.
Cmds now fire as normal, and a custom check can be performed by the cmd
*manager* rather than within the cmd itself. Failure of the check raises
an error in the transaction, and when the transaction is over, the
presence of an error triggers an immediate rollback and free.
- It clearly packages any corrective algorithms which we may want to
fire into separate cmds, which will also be grouped within the
transaction and therefore easily undo-able.
Also attached are two new files and associated makefile entries -
src/planner-error-dialog.c and src/planner-error-dialog.h, which collect
together common error handling from several files and are referenced in
my planner-cmd-manager patch.
Using this new transaction functionality, I have been able to finish my
release of planner which blocks any actions that result in overload,
simply by wrapping every cmd fired by an action in a check-catch
transaction.
I am doing a couple of final bug-fixes to this overallocation_prohibited
release, and should be able to send patches pending approval/comments on
the resource dialog patch I sent last week, which ties into the final
overload-checking algorithm and is a source of overload in itself (item
7 above).
Thanks,
Lee
Index: ChangeLog
===================================================================
--- ChangeLog (revision 940)
+++ ChangeLog (working copy)
@@ -1,3 +1,32 @@
+2008-11-30 Lee Baylis <lee leebaylis co uk>
+
+ * libplanner/mrp-error.h:
+ Added error conditions for transactions and resource overloading
+ * src/Makefile.am:
+ * src/Makefile.win32:
+ Added two new files, planner-error-dialog.c and planner-error-dialog.h
+ * src/planner-error-dialog.c:
+ * src/planner-error-dialog.h:
+ Collected common error pop-up routine from planner-task-dialog
+ and planner-task-tree.
+ * src/planner-cmd-manager.c (cmd_manager_ensure_limit),
+ (cmd_manager_free_after_current), (cmd_manager_insert),
+ (transaction_cmd_undo), (transaction_cmd_do),
+ (planner_cmd_manager_begin_transaction),
+ (planner_cmd_manager_begin_check_catch_transaction),
+ (planner_cmd_manager_end_transaction):
+ * src/planner-cmd-manager.h:
+ - Collected the routine for freeing cmds into a function
+ - Made TransactionCmd a dedicated Cmd struct with members useful
+ for handling transactions
+ - Worked on transaction support so that transactions which fail are
+ rolled back and freed.
+ - Added a new type of transaction, check_catch transaction, which
+ offers the facility for a typecast check function to be ran
+ every time a cmd is added to the transaction, and a typecast catch
+ function to be specified which runs should the check condition be
+ met.
+
2008-11-05 Maurice van der Pot <griffon26 kfk4ever com>
* libplanner/mrp-parser.c: Removed unused function.
Index: libplanner/mrp-error.h
===================================================================
--- libplanner/mrp-error.h (revision 940)
+++ libplanner/mrp-error.h (working copy)
@@ -3,6 +3,7 @@
* Copyright (C) 2002 CodeFactory AB
* Copyright (C) 2002 Richard Hult <richard imendio com>
* Copyright (C) 2002 Mikael Hallendal <micke imendio com>
+ * Copyright (C) 2008 Lee Baylis <lee leebaylis co uk>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -41,7 +42,11 @@
MRP_ERROR_SAVE_WRITE_FAILED,
MRP_ERROR_INVALID_URI,
-
+
+ MRP_ERROR_TRANSACTION_REDO_FAILED,
+ MRP_ERROR_PROJECT_FAILS_CHECK_BEFORE_STARTING_TRANSACTION,
+ MRP_ERROR_ACTION_OVERLOADS_RESOURCE,
+
/* General error (should avoid using this). */
MRP_ERROR_FAILED
} MrpError;
Index: src/planner-cmd-manager.c
===================================================================
--- src/planner-cmd-manager.c (revision 940)
+++ src/planner-cmd-manager.c (working copy)
@@ -1,6 +1,7 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* Copyright (C) 2003-2004 Imendio AB
+ * Copyright (C) 2008 Lee Baylis <lee leebaylis co uk>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -23,14 +24,26 @@
#include <glib/gi18n.h>
#include "planner-cmd-manager.h"
#include "planner-marshal.h"
+#include "planner-error-dialog.h"
+typedef struct {
+ PlannerCmd base;
+
+ PlannerCmdCheckFunc check_func;
+ PlannerCmdCatchCmdFunc catch_cmd_func;
+
+ MrpProject *project;
+ gboolean transaction_failed;
+ GError *potential_error;
+} TransactionCmd;
+
struct _PlannerCmdManagerPriv {
gint limit;
GList *list;
GList *current;
- gboolean inside_transaction;
+ TransactionCmd *transaction;
};
@@ -274,7 +287,7 @@
/* Don't try to cut when inside a transaction to make this a bit
* simpler.
*/
- if (priv->inside_transaction) {
+ if (priv->transaction) {
return;
}
@@ -313,14 +326,34 @@
}
}
+static GList *
+cmd_manager_free_after_current (PlannerCmdManager *manager)
+{
+ PlannerCmdManagerPriv *priv;
+ GList *current;
+
+ priv = manager->priv;
+ current = priv->current;
+
+ if (current && current->prev) {
+ current->prev->next = NULL;
+ current->prev = NULL;
+ }
+
+ g_list_foreach (priv->list, (GFunc) cmd_manager_free_func, NULL);
+ g_list_free (priv->list);
+
+ return priv->list = current;
+}
+
static gboolean
cmd_manager_insert (PlannerCmdManager *manager,
PlannerCmd *cmd,
gboolean run_do)
{
PlannerCmdManagerPriv *priv;
- GList *current;
gboolean retval;
+ PlannerCmd *catch_cmd;
priv = manager->priv;
@@ -328,18 +361,7 @@
/* Need to wipe the cmd history added after the current
* element.
*/
-
- current = priv->current;
-
- if (current && current->prev) {
- current->prev->next = NULL;
- current->prev = NULL;
- }
-
- g_list_foreach (priv->list, (GFunc) cmd_manager_free_func, NULL);
- g_list_free (priv->list);
-
- priv->list = current;
+ priv->list = cmd_manager_free_after_current(manager);
}
cmd_manager_ensure_limit (manager);
@@ -351,14 +373,89 @@
if (run_do && cmd->do_func) {
retval = cmd->do_func (cmd);
+
+ cmd_manager_dump (manager);
+ state_changed (manager);
+
+ /* Don't bother with transaction logic if the transaction
+ * has failed already */
+ if (priv->transaction && !priv->transaction->transaction_failed){
+ if (!retval){
+ /* The command failed independently of the
+ * results of any transaction check function.
+ * Planner already has (buggy) error handling
+ * in place for this on a per cmd basis, and
+ * we don't want to duplicate that handling
+ * here.
+
+ * FIXME: the per cmd error handling provided
+ * by planner is often buggy and tends to
+ * leave redundant undo cmds in the manager
+ * which cause warnings when ran by a user.
+ * Try adding a link dependency loop between
+ * two tasks, then edit->undo it for an
+ * example. One fix would be to convert
+ * such buggy routines over to using
+ * check_catch transaction support instead,
+ * but if this is done, the transaction code
+ * will need modifying to handle such
+ * failures instead of ignoring them.
+
+ * Until such conversion, however, the
+ * transaction just needs to fail and do
+ * nothing else if the cmd fails, and we
+ * don't want the transaction catch error
+ * appearing in addition to the per cmd error
+ * and confusing the user.
+ */
+ if (priv->transaction->potential_error){
+ g_error_free(priv->transaction->potential_error);
+ priv->transaction->potential_error = NULL;
+ }
+
+ } else if (priv->transaction->check_func) {
+
+ /* Catch functions potentially change the
+ * state of the project so should create a
+ * cmd and perform an insert_and_do all of
+ * their own:
+ *
+ * - maintain a distinct command history
+ * within the transaction for each catch
+ * action which is taken ("undo reallocate
+ * resource", etc)
+ *
+ * - if only the action which caused the
+ * catch is un-done, calling a simple
+ * task_recalc on resulting data won't
+ * necessarily undo whatever catch action
+ * was taken, so a saved undo state is
+ * required for each catch action
+ */
+
+ retval = 1 - priv->transaction->check_func(cmd);
+ if (!retval){
+ catch_cmd = priv->transaction->catch_cmd_func(cmd);
+ if (catch_cmd){
+ retval = TRUE;
+ }
+ }
+ }
+
+ if (!retval){
+ /* Whether it was the cmd or the catch that
+ * failed, mark the whole transaction failed
+ */
+ priv->transaction->transaction_failed = TRUE;
+ }
+ }
+
} else {
retval = TRUE;
+ cmd_manager_dump (manager);
+ state_changed (manager);
}
- cmd_manager_dump (manager);
-
- state_changed (manager);
-
return retval;
}
@@ -444,60 +541,82 @@
* Transaction commands
*/
-/* This function is used for the do_func of a BEGIN_TRANSACTION command. It
- * loops through all subcommands of a transaction and executes their functions
- * until it encounters an END_TRANSACTION command.
+/* This function is used for the undo_func of an END_TRANSACTION command. It
+ * loops through all subcommands of a transaction and executes their undo
+ * functions until it encounters a BEGIN_TRANSACTION command.
*/
-static gboolean
-transaction_cmd_do (PlannerCmd *cmd)
+
+static void
+transaction_cmd_undo (PlannerCmd *cmd)
{
PlannerCmd *cmd_sub;
-
+
while (1) {
- cmd_sub = get_redo_cmd (cmd->manager, TRUE);
+ cmd_sub = get_undo_cmd (cmd->manager, TRUE);
if (!cmd_sub) {
break;
}
- if (cmd_sub->type == PLANNER_CMD_TYPE_END_TRANSACTION) {
+ if (cmd_sub->type == PLANNER_CMD_TYPE_BEGIN_TRANSACTION) {
break;
}
- if (cmd_sub->do_func) {
- cmd_sub->do_func (cmd_sub);
+ if (cmd_sub->undo_func) {
+ cmd_sub->undo_func (cmd_sub);
}
g_assert (cmd_sub->type == PLANNER_CMD_TYPE_NORMAL);
}
-
- /* FIXME: need to make sure we handle transactions that doesn't work. */
-
- return TRUE;
}
-static void
-transaction_cmd_undo (PlannerCmd *cmd)
+static gboolean
+transaction_cmd_do (PlannerCmd *cmd)
{
+ gboolean success = TRUE;
PlannerCmd *cmd_sub;
-
+ GError *error = NULL;
while (1) {
- cmd_sub = get_undo_cmd (cmd->manager, TRUE);
+ cmd_sub = get_redo_cmd (cmd->manager, TRUE);
if (!cmd_sub) {
break;
}
- if (cmd_sub->type == PLANNER_CMD_TYPE_BEGIN_TRANSACTION) {
+ if (cmd_sub->type == PLANNER_CMD_TYPE_END_TRANSACTION) {
break;
}
- if (cmd_sub->undo_func) {
- cmd_sub->undo_func (cmd_sub);
+ if (cmd_sub->do_func) {
+ if (!cmd_sub->do_func (cmd_sub)){
+ success = FALSE;
+ break;
+ }
}
g_assert (cmd_sub->type == PLANNER_CMD_TYPE_NORMAL);
}
+
+ /* Handle transactions that don't work.
+ * Note that transaction_cmd_do is only ever called as a redo function,
+ * so we don't need to take any special action here other than rolling
+ * back the transaction and alerting the user.
+ * Special action should only need to be taken if the transaction
+ * fails the FIRST time it is ran -- see cmd_manager_insert for
+ * that scenario. */
+ if (!success){
+ g_set_error(&error,
+ MRP_ERROR,
+ MRP_ERROR_TRANSACTION_REDO_FAILED,
+ _("Redo failed trying to %s"),
+ cmd_sub->name);
+ planner_error_dialog_show_and_free(NULL, error);
+
+ g_warning ("Redo of transaction failed. Since this is a redo, the transaction succeeded the first time it ran, so this should not happen. Likely an bug in cmd_manager_insert, cmd_manager_free_after, or one of the transaction functions.");
+ transaction_cmd_undo(cmd_sub);
+ }
+
+ return success;
}
gboolean
@@ -505,33 +624,95 @@
const gchar *name)
{
PlannerCmdManagerPriv *priv;
- PlannerCmd *cmd;
-
+ PlannerCmd *cmd_base;
+ TransactionCmd *cmd;
+
g_return_val_if_fail (PLANNER_IS_CMD_MANAGER (manager), FALSE);
priv = manager->priv;
- if (priv->inside_transaction) {
+ if (priv->transaction) {
g_warning ("Already inside transaction.");
return FALSE;
}
- priv->inside_transaction = TRUE;
+ cmd_base = planner_cmd_new (TransactionCmd,
+ name,
+ transaction_cmd_do,
+ transaction_cmd_undo,
+ NULL);
- cmd = planner_cmd_new (PlannerCmd,
- name,
- transaction_cmd_do,
- transaction_cmd_undo,
- NULL);
+ cmd_base->type = PLANNER_CMD_TYPE_BEGIN_TRANSACTION;
- cmd->type = PLANNER_CMD_TYPE_BEGIN_TRANSACTION;
+ cmd = (TransactionCmd *) cmd_base;
- cmd_manager_insert (manager, cmd, FALSE);
+ priv->transaction = cmd;
+
+ cmd_manager_insert (manager, cmd_base, FALSE);
return TRUE;
}
gboolean
+planner_cmd_manager_begin_check_catch_transaction (PlannerCmdManager *manager,
+ MrpProject *project,
+ const gchar *name,
+ GError *potential_error,
+ PlannerCmdCheckFunc checkfunc,
+ PlannerCmdCatchCmdFunc catch_cmd_func)
+{
+ PlannerCmdManagerPriv *priv;
+ PlannerCmd *cmd_base;
+ TransactionCmd *cmd;
+
+ g_return_val_if_fail (PLANNER_IS_CMD_MANAGER (manager), FALSE);
+
+ priv = manager->priv;
+
+ if (priv->transaction) {
+ g_warning ("Already inside transaction.");
+ return FALSE;
+ }
+
+ cmd_base = planner_cmd_new (TransactionCmd,
+ name,
+ transaction_cmd_do,
+ transaction_cmd_undo,
+ NULL);
+
+ cmd_base->type = PLANNER_CMD_TYPE_BEGIN_TRANSACTION;
+
+ cmd = (TransactionCmd *) cmd_base;
+
+ cmd->check_func = checkfunc;
+ cmd->catch_cmd_func = catch_cmd_func;
+
+ cmd->project = project;
+ cmd->potential_error = potential_error;
+
+ priv->transaction = cmd;
+
+ cmd_manager_insert (manager, cmd_base, FALSE);
+
+ if (cmd->check_func(cmd_base)){
+ /* Check condition failed before we've done anything. Let user know. */
+ GError *error = NULL;
+
+ cmd->transaction_failed = TRUE;
+
+ g_set_error(&error,
+ MRP_ERROR,
+ MRP_ERROR_PROJECT_FAILS_CHECK_BEFORE_STARTING_TRANSACTION,
+ _("Project is in a state which is forbidden before trying to '%s' - see next error message for more details"),
+ name);
+
+ planner_error_dialog_show_and_free(NULL, error);
+ }
+
+ return TRUE;
+}
+
+gboolean
planner_cmd_manager_end_transaction (PlannerCmdManager *manager)
{
PlannerCmdManagerPriv *priv;
@@ -542,7 +723,7 @@
priv = manager->priv;
- if (!priv->inside_transaction) {
+ if (!priv->transaction) {
g_warning ("Don't have transaction to end.");
return FALSE;
}
@@ -562,6 +743,25 @@
return FALSE;
}
+ if (priv->transaction->transaction_failed){
+ /* Tell the user */
+ if (priv->transaction->potential_error){
+ planner_error_dialog_show_and_free(NULL, priv->transaction->potential_error);
+ priv->transaction = NULL;
+ }
+
+ /* Roll back and free the transaction */
+ transaction_cmd_undo(priv->current->data);
+ priv->list = cmd_manager_free_after_current(manager);
+
+ cmd_manager_dump (manager);
+ state_changed (manager);
+
+ return FALSE;
+ }
+
+ /* Transaction succeeded */
+
cmd = planner_cmd_new (PlannerCmd,
begin_cmd->name,
transaction_cmd_do,
@@ -572,8 +772,14 @@
cmd_manager_insert (manager, cmd, FALSE);
- priv->inside_transaction = FALSE;
+ /* Don't need the error any longer */
+ if (priv->transaction->potential_error){
+ g_error_free(priv->transaction->potential_error);
+ priv->transaction->potential_error = NULL;
+ }
+ priv->transaction = NULL;
+
return TRUE;
}
Index: src/planner-cmd-manager.h
===================================================================
--- src/planner-cmd-manager.h (revision 940)
+++ src/planner-cmd-manager.h (working copy)
@@ -1,6 +1,7 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* Copyright (C) 2003 Imendio AB
+ * Copyright (C) 2008 Lee Baylis <lee leebaylis co uk>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -22,6 +23,7 @@
#define __PLANNER_CMD_MANAGER_H__
#include <glib-object.h>
+#include "libplanner/mrp-project.h"
#define PLANNER_TYPE_CMD_MANAGER (planner_cmd_manager_get_type ())
#define PLANNER_CMD_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PLANNER_TYPE_CMD_MANAGER, PlannerCmdManager))
@@ -45,9 +47,11 @@
typedef struct _PlannerCmd PlannerCmd;
-typedef gboolean (*PlannerCmdDoFunc) (PlannerCmd *cmd);
-typedef void (*PlannerCmdUndoFunc) (PlannerCmd *cmd);
-typedef void (*PlannerCmdFreeFunc) (PlannerCmd *cmd);
+typedef gboolean (*PlannerCmdDoFunc) (PlannerCmd *cmd);
+typedef void (*PlannerCmdUndoFunc) (PlannerCmd *cmd);
+typedef void (*PlannerCmdFreeFunc) (PlannerCmd *cmd);
+typedef gboolean (*PlannerCmdCheckFunc) (PlannerCmd *cmd);
+typedef PlannerCmd * (*PlannerCmdCatchCmdFunc) (PlannerCmd *cmd);
typedef enum {
PLANNER_CMD_TYPE_NORMAL = 0,
@@ -69,20 +73,26 @@
};
-GType planner_cmd_manager_get_type (void) G_GNUC_CONST;
-PlannerCmdManager *planner_cmd_manager_new (void);
-gboolean planner_cmd_manager_insert_and_do (PlannerCmdManager *manager,
- PlannerCmd *cmd);
-gboolean planner_cmd_manager_undo (PlannerCmdManager *manager);
-gboolean planner_cmd_manager_redo (PlannerCmdManager *manager);
-gboolean planner_cmd_manager_begin_transaction (PlannerCmdManager *manager,
- const gchar *name);
-gboolean planner_cmd_manager_end_transaction (PlannerCmdManager *manager);
-PlannerCmd * planner_cmd_new_size (gsize size,
- const gchar *name,
- PlannerCmdDoFunc do_func,
- PlannerCmdUndoFunc undo_func,
- PlannerCmdFreeFunc free_func);
+GType planner_cmd_manager_get_type (void) G_GNUC_CONST;
+PlannerCmdManager *planner_cmd_manager_new (void);
+gboolean planner_cmd_manager_insert_and_do (PlannerCmdManager *manager,
+ PlannerCmd *cmd);
+gboolean planner_cmd_manager_undo (PlannerCmdManager *manager);
+gboolean planner_cmd_manager_redo (PlannerCmdManager *manager);
+gboolean planner_cmd_manager_begin_transaction (PlannerCmdManager *manager,
+ const gchar *name);
+gboolean planner_cmd_manager_end_transaction (PlannerCmdManager *manager);
+PlannerCmd * planner_cmd_new_size (gsize size,
+ const gchar *name,
+ PlannerCmdDoFunc do_func,
+ PlannerCmdUndoFunc undo_func,
+ PlannerCmdFreeFunc free_func);
+gboolean planner_cmd_manager_begin_check_catch_transaction (PlannerCmdManager *manager,
+ MrpProject *project,
+ const gchar *name,
+ GError *potential_error,
+ PlannerCmdCheckFunc checkfunc,
+ PlannerCmdCatchCmdFunc catch_cmd_func);
#define planner_cmd_new(t,l,d,u,f) planner_cmd_new_size(sizeof(t),l,d,u,f)
Index: src/Makefile.am
===================================================================
--- src/Makefile.am (revision 940)
+++ src/Makefile.am (working copy)
@@ -60,6 +60,8 @@
planner-day-type-dialog.h \
planner-default-week-dialog.c \
planner-default-week-dialog.h \
+ planner-error-dialog.c \
+ planner-error-dialog.h \
planner-format.c \
planner-format.h \
planner-group-dialog.c \
Index: src/Makefile.win32
===================================================================
--- src/Makefile.win32 (revision 940)
+++ src/Makefile.win32 (working copy)
@@ -56,6 +56,7 @@
planner-conf-win32.c \
planner-day-type-dialog.c \
planner-default-week-dialog.c \
+ planner-error-dialog.c \
planner-format.c \
planner-group-dialog.c \
planner-group-model.c \
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* Copyright (C) 2008 Lee Baylis <lee leebaylis co uk>
*
* 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 2 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, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include <gtk/gtk.h>
#include "planner-error-dialog.h"
void
planner_error_dialog_show_and_free (GtkWindow *parent_dialog, GError *error)
{
GtkWidget *err_dialog;
err_dialog = gtk_message_dialog_new (parent_dialog,
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_ERROR,
GTK_BUTTONS_OK,
"%s", error->message);
gtk_dialog_run (GTK_DIALOG (err_dialog));
gtk_widget_destroy (err_dialog);
g_error_free (error);
}
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* Copyright (C) 2008 Lee Baylis <lee leebaylis co uk>
*
* 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 2 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, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __PLANNER_ERROR_DIALOG_H__
#define __PLANNER_ERROR_DIALOG_H__
#include <gtk/gtkwidget.h>
void planner_error_dialog_show_and_free (GtkWindow *parent_dialog, GError *error);
#endif /* __PLANNER_ERROR_DIALOG_H__ */
[
Date Prev][Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]