cmd manager transactions



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]