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