Re: [Fwd: [evolution-patches] [resend] patches for #20672 (gtkhtml and mailer)]



On Thu, 2003-11-06 at 16:02, Radek Doul�wrote: 
> 
> I thought about that bug again and I think we don't need any change on
> gtkhtml's side. I am attaching composer fix (autosave.fix) and your
> evolution-changed.diff patch. Could you test that the fix works for you?

It doesn't work very well; e.g. it doesn't autosave once after a
composer is created, and it degrades to autosaving every time after a
header change.

However, I was intrigued by the idea, and after a lot of thinking,
fiddling and testing, I've finally arrived at a solution which works
very well even without changing gtkhtml. :) The only minor caveat is
that if you e.g.

      * save the message (as a draft or file)
      * make changes
      * let it autosave
      * undo the changes
      * close the composer

it will no longer realise that the message is actually saved and prompt
about unsaved changes; similarly for autosave-change-save-undo-autosave,
but that's even less of an issue. Negligible corner cases IMHO.

I'm curious what you guys think about this.


The other patch you posted again is as obviously correct as ever. :)


-- 
Earthling Michel D�er      |     Debian (powerpc), X and DRI developer
Software libre enthusiast    |   http://svcs.affero.net/rm.php?r=daenzer
Index: ChangeLog
===================================================================
RCS file: /cvs/gnome/evolution/composer/ChangeLog,v
retrieving revision 1.544.2.16
diff -p -u -r1.544.2.16 ChangeLog
--- ChangeLog	6 Oct 2003 17:07:16 -0000	1.544.2.16
+++ ChangeLog	9 Nov 2003 00:38:15 -0000
@@ -0,0 +0,28 @@
+2003-11-08  Michel D�er  <michel daenzer net>
+
+	* e-msg-composer.h: e_msg_composer_is_dirty prototype removed.
+	(struct _EMsgComposerSaveState): Added.
+	(enum _EMsgComposerState): Added.
+	(struct _EMsgComposer): Replace has_changed field by array of
+	_EMsgComposerSaveState structs.
+
+	* e-msg-composer.c (e_msg_composer_do_unset_changed): Added, clear
+	the has_changed flag and set the had_undo flag to whether the
+	editor engine has an undo queue for the specified state.
+	(e_msg_composer_is_dirty): Make static; don't just test for the
+	presence of an undo queue in the editor engine but compare to
+	remembered state.
+	(save): Preserve autosave state.
+	(autosave_save_draft): Call e_msg_composer_is_dirty() for
+	STATE_AUTOSAVE to only autosave when necessary. Fixes bug #20672.
+	Preserve save state.
+	(menu_file_save_draft_cb): Preserve autosave state.
+	(do_exit): Call e_msg_composer_is_dirty() for STATE_SAVE to only
+	prompt about unsaved changes when necessary. Preserve autosave
+	state.
+	(init): Initialize save and autosave states.
+	(e_msg_composer_set_changed): Set save and autosave has_changed
+	flags.
+	(e_msg_composer_unset_changed): Call new
+	e_msg_composer_do_unset_changed() function for STATE_SAVE.
+
Index: e-msg-composer.c
===================================================================
RCS file: /cvs/gnome/evolution/composer/e-msg-composer.c,v
retrieving revision 1.395.2.8
diff -p -u -r1.395.2.8 e-msg-composer.c
--- e-msg-composer.c	6 Oct 2003 17:07:16 -0000	1.395.2.8
+++ e-msg-composer.c	9 Nov 2003 00:38:16 -0000
@@ -1142,6 +1142,41 @@ set_editor_text (EMsgComposer *composer,
 	bonobo_object_unref (BONOBO_OBJECT (stream));
 }
 
+static void
+e_msg_composer_do_unset_changed (EMsgComposer *composer, _EMsgComposerState state)
+{
+	CORBA_Environment ev;
+
+	if (state >= STATE_LAST)
+		return;
+
+	CORBA_exception_init (&ev);
+	composer->state[state].had_undo = GNOME_GtkHTML_Editor_Engine_hasUndo (composer->editor_engine, &ev);
+	CORBA_exception_free (&ev);
+
+	composer->state[state].has_changed = FALSE;
+}
+
+static gboolean
+e_msg_composer_is_dirty (EMsgComposer *composer, _EMsgComposerState state)
+{
+	CORBA_Environment ev;
+	gboolean rv;
+
+	if (state >= STATE_LAST || composer->state[state].has_changed)
+		return TRUE;
+
+	CORBA_exception_init (&ev);
+	if (GNOME_GtkHTML_Editor_Engine_hasUndo (composer->editor_engine, &ev))
+		rv = !composer->state[state].had_undo ||
+		     !GNOME_GtkHTML_Editor_Engine_runCommand (composer->editor_engine, "is-saved", &ev);
+	else
+		rv = composer->state[state].had_undo;
+	CORBA_exception_free (&ev);
+
+	return rv;
+}
+
 /* Commands.  */
 
 static void
@@ -1218,9 +1253,14 @@ save (EMsgComposer *composer, const char
 		
 		e_notice (composer, GTK_MESSAGE_ERROR, _("Error saving file: %s"), tmp);
 		g_free(tmp);
-	} else
+	} else {
+		gboolean dirty_autosave = e_msg_composer_is_dirty (composer, STATE_AUTOSAVE);
 		GNOME_GtkHTML_Editor_Engine_runCommand (composer->editor_engine, "saved", &ev);
-
+		e_msg_composer_do_unset_changed (composer, STATE_SAVE);
+		/* Restore autosave state */
+		if (dirty_autosave)
+			composer->state[STATE_AUTOSAVE].has_changed = TRUE;
+	}
 	CORBA_exception_free (&ev);
 	
 	g_free (filename);
@@ -1269,7 +1309,7 @@ autosave_save_draft (EMsgComposer *compo
 	int fd, camelfd;
 	gboolean success = TRUE;
 	
-	if (!e_msg_composer_is_dirty (composer))
+	if (!e_msg_composer_is_dirty (composer, STATE_AUTOSAVE))
 		return TRUE;
 	
 	fd = composer->autosave_fd;
@@ -1320,6 +1360,16 @@ autosave_save_draft (EMsgComposer *compo
 			  _("Error autosaving message: %s\n %s"), file, strerror(errno));
 		
 		success = FALSE;
+	} else {
+		gboolean dirty_save = e_msg_composer_is_dirty (composer, STATE_SAVE);
+		CORBA_Environment ev;
+		CORBA_exception_init (&ev);
+		GNOME_GtkHTML_Editor_Engine_runCommand (composer->editor_engine, "saved", &ev);
+		CORBA_exception_free (&ev);
+		e_msg_composer_do_unset_changed (composer, STATE_AUTOSAVE);
+		/* Restore save state */
+		if (dirty_save)
+			composer->state[STATE_SAVE].has_changed = TRUE;
 	}
 	
 	camel_object_unref (stream);
@@ -1552,8 +1602,13 @@ autosave_manager_unregister (AutosaveMan
 static void
 menu_file_save_draft_cb (BonoboUIComponent *uic, void *data, const char *path)
 {
+	EMsgComposer *composer = E_MSG_COMPOSER (data);
+	gboolean dirty_autosave = e_msg_composer_is_dirty (composer, STATE_AUTOSAVE);
 	g_signal_emit (data, signals[SAVE_DRAFT], 0, FALSE);
-	e_msg_composer_unset_changed (E_MSG_COMPOSER (data));
+	e_msg_composer_do_unset_changed (composer, STATE_SAVE);
+	/* Restore autosave state */
+	if (dirty_autosave)
+		composer->state[STATE_AUTOSAVE].has_changed = TRUE;
 }
 
 /* Exit dialog.  (Displays a "Save composition to 'Drafts' before exiting?" warning before actually exiting.)  */
@@ -1565,7 +1620,7 @@ do_exit (EMsgComposer *composer)
 	GtkWidget *dialog;
 	int button;
 	
-	if (!e_msg_composer_is_dirty (composer)) {
+	if (!e_msg_composer_is_dirty (composer, STATE_SAVE)) {
 		gtk_widget_destroy (GTK_WIDGET (composer));
 		return;
 	}
@@ -1594,8 +1649,14 @@ do_exit (EMsgComposer *composer)
 	switch (button) {
 	case GTK_RESPONSE_YES:
 		/* Save */
-		g_signal_emit (GTK_OBJECT (composer), signals[SAVE_DRAFT], 0, TRUE);
-		e_msg_composer_unset_changed (composer);
+		{
+			gboolean dirty_autosave = e_msg_composer_is_dirty (composer, STATE_AUTOSAVE);
+			g_signal_emit (GTK_OBJECT (composer), signals[SAVE_DRAFT], 0, TRUE);
+			e_msg_composer_do_unset_changed (composer, STATE_SAVE);
+			/* Restore autosave state */
+			if (dirty_autosave)
+				composer->state[STATE_AUTOSAVE].has_changed = TRUE;
+		}
 		break;
 	case GTK_RESPONSE_NO:
 		/* Don't save */
@@ -2706,7 +2772,10 @@ init (EMsgComposer *composer)
 	composer->smime_sign               = FALSE;
 	composer->smime_encrypt            = FALSE;
 	
-	composer->has_changed              = FALSE;
+	composer->state[STATE_SAVE].has_changed     = FALSE;
+	composer->state[STATE_SAVE].had_undo        = FALSE;
+	composer->state[STATE_AUTOSAVE].has_changed = TRUE;
+	composer->state[STATE_AUTOSAVE].had_undo    = FALSE;
 	
 	composer->redirect                 = FALSE;
 	
@@ -4884,14 +4953,16 @@ e_msg_composer_guess_mime_type (const ch
  * @composer: An EMsgComposer object.
  *
  * Mark the composer as changed, so before the composer gets destroyed
- * the user will be prompted about unsaved changes.
+ * the user will be prompted about unsaved changes, and the message will be
+ * autosaved.
  **/
 void
 e_msg_composer_set_changed (EMsgComposer *composer)
 {
 	g_return_if_fail (E_IS_MSG_COMPOSER (composer));
-	
-	composer->has_changed = TRUE;
+
+	composer->state[STATE_SAVE].has_changed = TRUE;
+	composer->state[STATE_AUTOSAVE].has_changed = TRUE;
 }
 
 
@@ -4906,24 +4977,8 @@ void
 e_msg_composer_unset_changed (EMsgComposer *composer)
 {
 	g_return_if_fail (E_IS_MSG_COMPOSER (composer));
-	
-	composer->has_changed = FALSE;
-}
-
-
-gboolean
-e_msg_composer_is_dirty (EMsgComposer *composer)
-{
-	CORBA_Environment ev;
-	gboolean rv;
-	
-	CORBA_exception_init (&ev);
-	rv = composer->has_changed
-		|| (GNOME_GtkHTML_Editor_Engine_hasUndo (composer->editor_engine, &ev) &&
-		    !GNOME_GtkHTML_Editor_Engine_runCommand (composer->editor_engine, "is-saved", &ev));
-	CORBA_exception_free (&ev);
 
-	return rv;
+	e_msg_composer_do_unset_changed (composer, STATE_SAVE);
 }
 
 
Index: e-msg-composer.h
===================================================================
RCS file: /cvs/gnome/evolution/composer/e-msg-composer.h,v
retrieving revision 1.83
diff -p -u -r1.83 e-msg-composer.h
--- e-msg-composer.h	20 May 2003 18:26:09 -0000	1.83
+++ e-msg-composer.h	9 Nov 2003 00:38:16 -0000
@@ -50,6 +50,16 @@ extern "C" {
 #define E_IS_MSG_COMPOSER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), E_TYPE_MSG_COMPOSER))
 
 
+struct _EMsgComposerSaveState {
+	guint32 has_changed : 1;
+	guint32 had_undo    : 1;
+};
+
+typedef enum {
+	STATE_SAVE,
+	STATE_AUTOSAVE,
+	STATE_LAST
+} _EMsgComposerState;
 
 struct _EMsgComposer {
 	BonoboWindow parent;
@@ -93,7 +103,8 @@ struct _EMsgComposer {
 	guint32 view_bcc               : 1;
 	guint32 view_cc                : 1;
 	guint32 view_subject           : 1;
-	guint32 has_changed            : 1;
+
+	struct _EMsgComposerSaveState state[STATE_LAST];
 	
 	guint32 mode_post              : 1;
 	
@@ -180,7 +191,6 @@ void                     e_msg_composer_
 char                    *e_msg_composer_guess_mime_type                  (const char        *file_name);
 void                     e_msg_composer_set_changed                      (EMsgComposer      *composer);
 void                     e_msg_composer_unset_changed                    (EMsgComposer      *composer);
-gboolean                 e_msg_composer_is_dirty                         (EMsgComposer      *composer);
 void                     e_msg_composer_set_enable_autosave              (EMsgComposer      *composer,
 									  gboolean           enabled);
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]