Update of /cvsroot/mahogany/M/src/gui
In directory usw-pr-cvs1:/tmp/cvs-serv29688/src/gui

Modified Files:
        wxComposeView.cpp 
Log Message:
added autosaving composer windows

Index: wxComposeView.cpp
===================================================================
RCS file: /cvsroot/mahogany/M/src/gui/wxComposeView.cpp,v
retrieving revision 1.259
retrieving revision 1.260
diff -b -u -2 -r1.259 -r1.260
--- wxComposeView.cpp   18 Mar 2002 13:01:00 -0000      1.259
+++ wxComposeView.cpp   18 Mar 2002 22:37:42 -0000      1.260
@@ -50,11 +50,13 @@
 #  include <wx/menu.h>
 #  include <wx/stattext.h>
+#  include <wx/textctrl.h>
 
 #  include <ctype.h>          // for isspace()
 #endif
 
-#include <wx/textctrl.h>
+#include <wx/filename.h>
 #include <wx/file.h>
 #include <wx/ffile.h>
+#include <wx/dir.h>
 #include <wx/process.h>
 #include <wx/mimetype.h>
@@ -148,5 +150,13 @@
 
 // the header used to indicate that a message is our draft
-#define DRAFT_HEADER "X-M-Draft"
+#define HEADER_IS_DRAFT "X-M-Draft"
+
+// the header used for storing the composer geometry
+#define HEADER_GEOMETRY "X-M-Geometry"
+
+// the possible values for HEADER_GEOMETRY
+#define GEOMETRY_ICONIZED "I"
+#define GEOMETRY_MAXIMIZED "M"
+#define GEOMETRY_FORMAT "%dx%d-%dx%d"
 
 // the composer frame title
@@ -160,4 +170,12 @@
 
 // ----------------------------------------------------------------------------
+// globals
+// ----------------------------------------------------------------------------
+
+M_LIST(ComposerList, wxComposeView *);
+
+static ComposerList gs_listOfAllComposers;
+
+// ----------------------------------------------------------------------------
 // private functions
 // ----------------------------------------------------------------------------
@@ -1065,7 +1083,8 @@
       else if ( ignoredHeaders.Index(name) == wxNOT_FOUND )
       {
-         // compare case sensitively here as we always write DRAFT_HEADER in
+         // compare case sensitively here as we always write HEADER_IS_DRAFT in
          // the same case
-         if ( names[n] == DRAFT_HEADER )
+         name = names[n];
+         if ( name == HEADER_IS_DRAFT )
          {
             cv->SetDraft(msg);
@@ -1090,4 +1109,31 @@
             }
          }
+         else if ( name == HEADER_GEOMETRY )
+         {
+            // restore the composer geometry
+            wxFrame *frame = cv->GetFrame();
+            String value = values[n];
+            if ( value == GEOMETRY_ICONIZED )
+            {
+               frame->Iconize();
+            }
+            else if ( value == GEOMETRY_MAXIMIZED )
+            {
+               frame->Maximize();
+            }
+            else // not iconized, not maximized
+            {
+               int x, y, w, h;
+               if ( sscanf(value, GEOMETRY_FORMAT, &x, &y, &w, &h) == 4 )
+               {
+                  frame->SetSize(x, y, w, h);
+               }
+               else // bad header format
+               {
+                  wxLogDebug("Corrupted " HEADER_GEOMETRY " header '%s'.",
+                             value.c_str());
+               }
+            }
+         }
          else // just another header
          {
@@ -1114,9 +1160,10 @@
                              MessageKind kind,
                              wxWindow *parent)
-             : wxMFrame(name,parent)
+             : wxMFrame(name, parent)
 {
+   gs_listOfAllComposers.push_back(this);
+
    m_mode = mode;
    m_kind = kind;
-   m_name = name;
    m_pidEditor = 0;
    m_procExtEdit = NULL;
@@ -1130,4 +1177,6 @@
    m_rcptTypeLast = Recipient_To;
 
+   m_isModified = false;
+
    m_editor = NULL;
    m_encoding = wxFONTENCODING_SYSTEM;
@@ -1168,4 +1217,30 @@
    SafeDecRef(m_OriginalMessage);
    SafeDecRef(m_DraftMessage);
+
+   for ( ComposerList::iterator i = gs_listOfAllComposers.begin(); ; ++i )
+   {
+      if ( i == gs_listOfAllComposers.end() )
+      {
+         FAIL_MSG( "composer not in the list of all composers?" );
+
+         break;
+      }
+
+      if ( *i == this )
+      {
+         gs_listOfAllComposers.erase(i);
+
+         break;
+      }
+   }
+
+   if ( !m_filenameAutoSave.empty() )
+   {
+      if ( !wxRemoveFile(m_filenameAutoSave) )
+      {
+         wxLogSysError(_("Failed to remove stale composer autosave file '%s'"),
+                       m_filenameAutoSave.c_str());
+      }
+   }
 }
 
@@ -2084,5 +2159,5 @@
       canClose = false;
    }
-   else if ( m_editor->IsModified() )
+   else if ( IsModified() )
    {
       // ask the user if he wants to save the changes
@@ -2094,7 +2169,5 @@
                           "You may also choose \"Cancel\" to not close this "
                           "window at all."),
-                        this, // parent
-                        MDIALOG_YESNOTITLE,
-                        M_DLG_NO_DEFAULT
+                        this  // parent
                       );
 
@@ -2194,5 +2267,5 @@
 
       case WXMENU_COMPOSE_EVAL_TEMPLATE:
-         if ( !m_editor->IsModified() )
+         if ( !IsModified() )
          {
             // remove our prompt
@@ -3233,4 +3306,10 @@
 {
    m_editor->ResetDirty();
+   m_isModified = false;
+}
+
+bool wxComposeView::IsModified() const
+{
+   return m_isModified || m_editor->IsModified();
 }
 
@@ -3310,4 +3389,7 @@
       return false;
 
+   if ( !READ_CONFIG(m_Profile, MP_DRAFTS_AUTODELETE) )
+      return false;
+
    // NB: GetFolder() doesn't IncRef() the result, so don't DecRef() it
    MailFolder *mf = m_DraftMessage->GetFolder();
@@ -3327,4 +3409,42 @@
 }
 
+SendMessage *wxComposeView::BuildDraftMessage() const
+{
+   SendMessage *msg = BuildMessage();
+   if ( !msg )
+   {
+      wxLogError(_("Failed to create the message to save."));
+   }
+   else
+   {
+      // mark this message as our draft (the value doesn't matter)
+      msg->AddHeaderEntry(HEADER_IS_DRAFT, "Yes");
+
+      // save the composer geometry info
+      String value;
+      wxFrame *frame = ((wxComposeView *)this)->GetFrame();
+      if ( frame->IsIconized() )
+      {
+         value = GEOMETRY_ICONIZED;
+      }
+      else if ( frame->IsMaximized() )
+      {
+         value = GEOMETRY_MAXIMIZED;
+      }
+      else // normal position
+      {
+         int x, y, w, h;
+         frame->GetPosition(&x, &y);
+         frame->GetSize(&w, &h);
+
+         value.Printf(GEOMETRY_FORMAT, x, y, w, h);
+      }
+
+      msg->AddHeaderEntry(HEADER_GEOMETRY, value);
+   }
+
+   return msg;
+}
+
 // from upgrade.cpp, this forward decl will disappear once we move it somewhere
 // else (most likely MFolder?)
@@ -3339,15 +3459,11 @@
 bool wxComposeView::SaveAsDraft() const
 {
-   SendMessage_obj msg = BuildMessage();
+   SendMessage_obj msg = BuildDraftMessage();
    if ( !msg )
    {
-      wxLogError(_("Failed to create the message to save."));
-
+      // error message already given by BuildDraftMessage()
       return false;
    }
 
-   // mark this message as our draft
-   msg->AddHeaderEntry(DRAFT_HEADER, "Yes");
-
    // ensure that the "Drafts" folder we're going to save the message to exists
    String nameDrafts = READ_CONFIG(m_Profile, MP_DRAFTS_FOLDER);
@@ -3417,4 +3533,148 @@
       M_DLG_DISABLE
    );
+
+   return true;
+}
+
+// ----------------------------------------------------------------------------
+// wxComposeView auto save
+// ----------------------------------------------------------------------------
+
+/**
+  Returns the directory used for autosaved composer contents, with '/' at the
+  end
+ */
+static String GetComposerAutosaveDir()
+{
+   String name = mApplication->GetLocalDir();
+   name += "/composer/";
+
+   return name;
+}
+
+bool
+wxComposeView::AutoSave()
+{
+   if ( !m_editor->IsModified() )
+   {
+      // nothing to do
+      return true;
+   }
+
+   SendMessage_obj msg = BuildDraftMessage();
+   if ( !msg )
+      return false;
+
+   if ( m_filenameAutoSave.empty() )
+   {
+      // make sure the directory we use for these scratch files exists
+      String name = GetComposerAutosaveDir();
+      if ( !wxDir::Exists(name) )
+      {
+         if ( !wxMkdir(name, 0700) )
+         {
+            wxLogSysError(_("Failed to create the directory '%s' for the "
+                            "temporary composer files"), name.c_str());
+            return false;
+         }
+      }
+
+      // we need a unique file name during the life time of this object as this
+      // file is always going to be deleted if we're destroyed correctly, it
+      // can only be left if the program crashes
+      m_filenameAutoSave = name + String::Format("%05d%08x", getpid(), this);
+   }
+
+   // false means don't append, truncate
+   if ( !msg->WriteToFile(m_filenameAutoSave, false) )
+   {
+      // TODO: disable autosaving? we risk to give many such messages if
+      //       something is wrong...
+      wxLogError(_("Failed to automatically save the message."));
+
+      return false;
+   }
+
+   // mark the editor as not modified to avoid resaving it the next time
+   // unnecessary but remember internally that it was modified (we didn't
+   // really save it)
+   m_isModified = true;
+   m_editor->ResetDirty();
+
+   return true;
+}
+
+bool Composer::SaveAll()
+{
+   bool rc = true;
+   for ( ComposerList::iterator i = gs_listOfAllComposers.begin();
+         i != gs_listOfAllComposers.end();
+         ++i )
+   {
+      rc &= (*i)->AutoSave();
+   }
+
+   return rc;
+}
+
+bool Composer::RestoreAll()
+{
+   String name = GetComposerAutosaveDir();
+   if ( !wxDir::Exists(name) )
+   {
+      // nothing to do
+      return true;
+   }
+
+   wxDir dir;
+   if ( !dir.Open(name) )
+   {
+      wxLogError(_("Failed to check for interrupted messages."));
+
+      return false;
+   }
+
+   size_t nResumed = 0;
+
+   wxString filename;
+   bool cont = dir.GetFirst(&filename, "", wxDIR_FILES);
+   while ( cont )
+   {
+      filename = name + filename;
+
+      MFolder_obj folder(MFolder::CreateTemp("", MF_FILE, 0, filename));
+
+      cont = dir.GetNext(&filename);
+
+      if ( folder )
+      {
+         MailFolder_obj mf = MailFolder::OpenFolder(folder);
+         if ( mf )
+         {
+            // FIXME: assume UID of the first message in a new MBX folder is
+            //        always 1
+            Message_obj msg = mf->GetMessage(1);
+            if ( msg )
+            {
+               if ( EditMessage(mApplication->GetProfile(), msg.operator->()) )
+               {
+                  // ok!
+                  nResumed++;
+
+                  continue;
+               }
+            }
+         }
+      }
+
+      wxLogError(_("Failed to resume composing the message from file '%s'"),
+                 filename.c_str());
+   }
+
+   if ( nResumed )
+   {
+      wxLogMessage(_("%d previously interrupted composer windows have been "
+                     "restored"), nResumed);
+   }
 
    return true;


_______________________________________________
Mahogany-cvsupdates mailing list
[EMAIL PROTECTED]
https://lists.sourceforge.net/lists/listinfo/mahogany-cvsupdates

Reply via email to