[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kmail-devel
Subject:    [Patch] kmail template facility
From:       "Jonathan Marten" <jjm () keelhaul ! demon ! co ! uk>
Date:       2005-08-20 12:55:15
Message-ID: ovacjczs24.fsf () keelhaul ! local
[Download RAW message or body]

Here's my try at a feature that lots of people have apparently been
wanting for a long time: mail templates (bug 1015).  Maybe too late
for the 3.5 feature freeze, but hopefully suitable for inclusion in a
future KMail release.

There is a new special folder "templates"; messages can be copied into
here just like any other, or saved here using the 'Message - Save as
Template' menu option in the composer window.  This folder works
similarly to the "drafts" folder; double-clicking on a message or
choosing the "Use Template" option on the popup menu starts the
composer on a copy of that message, but does not of course delete the
original template message.

A template can also be used to insert text into a message being
composed, via the 'Message - Insert Template Text' menu option.  This
will display a list of template messages (subject and summary of start
of body); selecting one in this list and clicking "OK" will insert the
body text into the message being composed.  (The subject is ignored for
this operation).

There is (currently) no facility for inserting variable fields into the
inserted template, but IMHO I agree with the bug comments that
mail-merge does not really belong in KMail.

Still to do (if required): GUI for an identity-specific templates
folder (if required), and the option to have the templates folder on
an IMAP server.  I also haven't tested this facility with HTML
messages, but see no reason why it shouldn't work...

Patch follows (against KDE 3.4.2).  There are two new source files
(kmail/selecttemplatedialog.cpp and kmail/selecttemplatedialog.h) to
handle the insert selection list as above.  There are also some minor
changes to libkdepim (sorting of the templates folder in the folder
tree) and libkpimidentities (only needed if a per-identity template
folder is required).  The patch is also at
http://www.keelhaul.demon.co.uk/kde/mailtemplates.patch in case it
should get damaged in the post.

Enjoy...

-- patch starts ---------------------------------------------------------
--- kdepim/kmail/Makefile.am.tem	2005-08-17 17:51:27.000000000 +0100
+++ kdepim/kmail/Makefile.am	2005-08-18 16:37:18.000000000 +0100
@@ -116,6 +116,7 @@
                 recipientseditor.cpp \
                 recipientspicker.cpp kwindowpositioner.cpp \
                 distributionlistdialog.cpp expirypropertiesdialog.cpp \
+                selecttemplatedialog.cpp \
                 mailinglistpropertiesdialog.cpp newfolderdialog.cpp
 
 kmail_SOURCES = main.cpp
--- kdepim/kmail/kmcommands.cpp.tem	2005-05-23 13:11:54.000000000 +0100
+++ kdepim/kmail/kmcommands.cpp	2005-08-20 12:20:15.000000000 +0100
@@ -629,6 +629,35 @@
 }
 
 
+KMUseTemplateCommand::KMUseTemplateCommand( QWidget *parent, KMMessage *msg )
+  :KMCommand( parent, msg )
+{
+}
+
+KMCommand::Result KMUseTemplateCommand::execute()
+{
+  kdDebug(0) << k_funcinfo << endl;
+  KMMessage *msg = retrievedMessage();
+  if (!msg || !msg->parent() ||
+      !kmkernel->folderIsTemplates( msg->parent() ))
+    return Failed;
+
+  // Take a copy of the original message, which remains unchanged.
+  KMMessage *newMsg = new KMMessage;
+  newMsg->setComplete(msg->isComplete());
+  newMsg->fromString(msg->asString());
+  newMsg->setStatus(msg->status());
+
+  KMComposeWin *win = new KMComposeWin();
+  msg->setTransferInProgress(false); // From here on on, the composer owns the \
message. +  newMsg->setTransferInProgress(false);
+  win->setMsg(newMsg, FALSE, TRUE);
+  win->show();
+
+  return OK;
+}
+
+
 KMShowMsgSrcCommand::KMShowMsgSrcCommand( QWidget *parent,
   KMMessage *msg, bool fixedFont )
   :KMCommand( parent, msg ), mFixedFont( fixedFont )
--- kdepim/kmail/kmcommands.h.tem	2005-05-23 13:11:54.000000000 +0100
+++ kdepim/kmail/kmcommands.h	2005-08-20 12:20:08.000000000 +0100
@@ -282,6 +282,17 @@
   virtual Result execute();
 };
 
+class KDE_EXPORT KMUseTemplateCommand : public KMCommand
+{
+  Q_OBJECT
+
+public:
+  KMUseTemplateCommand( QWidget *parent, KMMessage *msg );
+
+private:
+  virtual Result execute();
+};
+
 class KDE_EXPORT KMShowMsgSrcCommand : public KMCommand
 {
   Q_OBJECT
--- kdepim/kmail/kmcomposerui.rc.tem	2005-05-23 13:11:54.000000000 +0100
+++ kdepim/kmail/kmcomposerui.rc	2005-08-17 17:12:19.000000000 +0100
@@ -1,4 +1,4 @@
-<!DOCTYPE kpartgui ><kpartgui version="25" name="kmcomposer" >
+<!DOCTYPE kpartgui ><kpartgui version="27" name="kmcomposer" >
  <MenuBar>
   <Menu noMerge="1" name="file" >
    <text>&amp;Message</text>
@@ -8,9 +8,11 @@
    <Action name="send_default" />
    <Action name="send_alternative" />
    <Action name="save_in_drafts" />
+   <Action name="save_in_templates" />
    <Separator/>
    <Action name="insert_file" />
    <Action name="insert_file_recent" />
+   <Action name="insert_template" />
    <Action name="file_print" />
    <Separator/>
    <Action name="file_close" />
--- kdepim/kmail/kmcomposewin.cpp.tem	2005-05-23 13:11:54.000000000 +0100
+++ kdepim/kmail/kmcomposewin.cpp	2005-08-18 16:44:03.000000000 +0100
@@ -45,6 +45,7 @@
 #include "kleo_util.h"
 #include "stl_util.h"
 #include "recipientseditor.h"
+#include "selecttemplatedialog.h"
 
 #include "attachmentcollector.h"
 #include "objecttreeparser.h"
@@ -1055,9 +1056,12 @@
                         actionCollection(), "send_alternative");
   }
 
-  (void) new KAction (i18n("Save in &Drafts Folder"), "filesave", 0,
+  (void) new KAction (i18n("Save as &Draft"), "filesave", 0,
                       this, SLOT(slotSaveDraft()),
                       actionCollection(), "save_in_drafts");
+  (void) new KAction (i18n("Save as &Template"), "filesave", 0,
+                      this, SLOT(slotSaveTemplate()),
+                      actionCollection(), "save_in_templates");
   (void) new KAction (i18n("&Insert File..."), "fileopen", 0,
                       this,  SLOT(slotInsertFile()),
                       actionCollection(), "insert_file");
@@ -1068,6 +1072,10 @@
 
   mRecentAction->loadEntries( KMKernel::config() );
 
+  (void) new KAction (i18n("Insert Template Te&xt..."), "filenew", 0,
+                      this,  SLOT(slotInsertTemplate()),
+                      actionCollection(), "insert_template");
+
   (void) new KAction (i18n("&Address Book"), "contents",0,
                       this, SLOT(slotAddrBook()),
                       actionCollection(), "addressbook");
@@ -3531,12 +3539,13 @@
 
 
 //----------------------------------------------------------------------------
-void KMComposeWin::doSend(int aSendNow, bool saveInDrafts)
+void KMComposeWin::doSend(int aSendNow, bool saveInDrafts, bool saveInTemplates)
 {
   mSendNow = aSendNow;
   mSaveInDrafts = saveInDrafts;
+  mSaveInTemplates = saveInTemplates;
 
-  if (!saveInDrafts)
+  if (!saveInDrafts && !saveInTemplates)
   {
     if ( KPIM::getFirstEmailAddress( from() ).isEmpty() ) {
       if ( !( mShowHeaders & HDR_FROM ) ) {
@@ -3631,9 +3640,9 @@
       (!hf.isEmpty() && (hf != mTransport->text(0))))
     mMsg->setHeaderField("X-KMail-Transport", mTransport->currentText());
 
-  mDisableBreaking = saveInDrafts;
+  mDisableBreaking = (saveInDrafts || saveInTemplates);
 
-  const bool neverEncrypt = ( saveInDrafts && GlobalSettings::neverEncryptDrafts() )
+  const bool neverEncrypt = ( (saveInDrafts || saveInTemplates) && \
GlobalSettings::neverEncryptDrafts() )  || mSigningAndEncryptionExplicitlyDisabled;
   connect( this, SIGNAL( applyChangesDone( bool ) ),
            SLOT( slotContinueDoSend( bool ) ) );
@@ -3739,6 +3748,52 @@
 	(static_cast<KMFolderImap*>(imapDraftsFolder->storage()))->getFolder();
       }
 
+    } else if (mSaveInTemplates) {
+      KMFolder* templatesFolder = 0, *imapTemplatesFolder = 0;
+      // get the templatesFolder
+      if ( !(*it)->templates().isEmpty() ) {
+        templatesFolder = kmkernel->folderMgr()->findIdString( (*it)->templates() );
+        if ( templatesFolder == 0 )
+          // This is *NOT* supposed to be "imapTemplatesFolder", because a
+          // dIMAP folder works like a normal folder
+          templatesFolder = kmkernel->dimapFolderMgr()->findIdString( \
(*it)->templates() ); +        if ( templatesFolder == 0 )
+          imapTemplatesFolder = kmkernel->imapFolderMgr()->findIdString( \
(*it)->templates() ); +        if ( !templatesFolder && !imapTemplatesFolder ) {
+          const KPIM::Identity & id = kmkernel->identityManager()
+            ->identityForUoidOrDefault( (*it)->headerField( "X-KMail-Identity" \
).stripWhiteSpace().toUInt() ); +          KMessageBox::information(0, i18n("The \
custom templates folder for identity " +                                           \
"\"%1\" does not exist (anymore); " +                                           \
"therefore, the default templates folder " +                                          \
"will be used.") +                                   .arg( id.identityName() ) );
+        }
+      }
+      if (imapTemplatesFolder && imapTemplatesFolder->noContent())
+	imapTemplatesFolder = 0;
+
+      if ( templatesFolder == 0 ) {
+	templatesFolder = kmkernel->templatesFolder();
+      } else {
+	templatesFolder->open();
+      }
+      kdDebug(5006) << "saveintemplates: templates=" << templatesFolder->name() << \
endl; +      if (imapTemplatesFolder)
+	kdDebug(5006) << "saveintemplates: imaptemplates="
+		      << imapTemplatesFolder->name() << endl;
+
+      sentOk = !(templatesFolder->addMsg((*it)));
+
+      //Ensure the templates message is correctly and fully parsed
+      templatesFolder->unGetMsg(templatesFolder->count() - 1);
+      (*it) = templatesFolder->getMsg(templatesFolder->count() - 1);
+
+      if (imapTemplatesFolder) {
+	// move the message to the imap-folder and highlight it
+	imapTemplatesFolder->moveMsg((*it));
+	(static_cast<KMFolderImap*>(imapTemplatesFolder->storage()))->getFolder();
+      }
+
     } else {
       (*it)->setTo( KMMessage::expandAliases( to() ));
       (*it)->setCc( KMMessage::expandAliases( cc() ));
@@ -3788,6 +3843,14 @@
 
 
 //----------------------------------------------------------------------------
+void KMComposeWin::slotSaveTemplate() {
+  kdDebug(0) << k_funcinfo << endl;
+  if ( mEditor->checkExternalEditorFinished() )
+    doSend( false, false, true );
+}
+
+
+//----------------------------------------------------------------------------
 void KMComposeWin::slotSendNow() {
   if ( !mEditor->checkExternalEditorFinished() )
     return;
@@ -4284,6 +4347,7 @@
 */
 void KMComposeWin::slotFolderRemoved(KMFolder* folder)
 {
+  // TODO: need to handle templates here?
   if ( (mFolder) && (folder->idString() == mFolder->idString()) )
   {
     mFolder = kmkernel->draftsFolder();
@@ -4417,6 +4481,35 @@
     alignRightAction->setChecked( ( a & AlignRight ) );
 }
 
+void KMComposeWin::slotInsertTemplate()
+{
+  kdDebug(0) << k_funcinfo << endl;
+
+  KMFolder *temFolder = kmkernel->templatesFolder();
+  if (!temFolder) return;
+
+  if (temFolder->count()==0)
+  {
+    KMessageBox::sorry(this,i18n("There are no templates available.\nCopy or save \
messages into the 'templates' folder in order to use them.")); +    return;
+  }
+
+  SelectTemplateDialog d(temFolder,this);
+
+  d.show();
+  if (d.exec())
+  {
+    QString s = d.selectedTemplateText();
+    if (!s.isEmpty()) mEditor->insert(s);
+  }
+}
+
+//=============================================================================
+//
+//   Class  KMEdit
+//
+//=============================================================================
+
 void KMEdit::contentsDragEnterEvent(QDragEnterEvent *e)
 {
     if (e->provides(MailListDrag::format()))
--- kdepim/kmail/kmcomposewin.h.tem	2005-05-23 13:11:54.000000000 +0100
+++ kdepim/kmail/kmcomposewin.h	2005-08-17 17:19:11.000000000 +0100
@@ -424,6 +424,7 @@
    * Returns true when saving was successful.
    */
   void slotSaveDraft();
+  void slotSaveTemplate();
   void slotNewComposer();
   void slotNewMailReader();
   void slotClose();
@@ -468,6 +469,11 @@
    */
   void slotInsertFile();
 
+  /**
+   * Insert the text of a template at the cursor position in the editor.
+   */
+  void slotInsertTemplate();
+
   void slotSetCharset();
   /**
    * Check spelling of text.
@@ -773,7 +779,7 @@
   /**
    * Send the message. Returns true if the message was sent successfully.
    */
-  void doSend(int sendNow=-1, bool saveInDrafts = false);
+  void doSend(int sendNow=-1, bool saveInDrafts = false, bool saveInTemplates = \
false);  
   /**
    * Returns the autosave interval in milliseconds (as needed for QTimer).
@@ -932,6 +938,7 @@
   // These are for passing on methods over the applyChanges calls
   int mSendNow;
   bool mSaveInDrafts;
+  bool mSaveInTemplates;
 
   // This is the temporary object that constructs the message out of the
   // window
--- kdepim/kmail/kmfoldertree.cpp.tem	2005-07-20 11:03:02.000000000 +0100
+++ kdepim/kmail/kmfoldertree.cpp	2005-08-16 14:35:40.000000000 +0100
@@ -117,6 +117,7 @@
       case SentMail: icon = "folder_sent_mail"; break;
       case Trash: icon = "trashcan_empty"; break;
       case Drafts: icon = "edit";break;
+      case Templates: icon = "filenew";break;
       default: icon = kmkernel->iCalIface().folderPixmap( type() ); break;
     }
     // non-root search folders
@@ -148,6 +149,7 @@
 
   if ( !mFolder || depth() == 0 || mFolder->isSystemFolder()
     || kmkernel->folderIsTrash( mFolder )
+    || kmkernel->folderIsTemplates( mFolder )
     || kmkernel->folderIsDraftOrOutbox( mFolder ) )
     pm = normalIcon( size );
 
@@ -190,6 +192,8 @@
       setType( SentMail );
     else if ( kmkernel->folderIsTrash( mFolder ) )
       setType( Trash );
+    else if ( kmkernel->folderIsTemplates( mFolder ) )
+      setType( Templates );
     else if( kmkernel->iCalIface().isResourceFolder(mFolder) )
       setType( kmkernel->iCalIface().folderType(mFolder) );
     // System folders on dimap or imap which are not resource folders are
@@ -784,6 +788,7 @@
       // ctrl- so we do this only if (confirm == true), which means we are doing
       // readOn.
       if ( fti->type() == KFolderTreeItem::Drafts ||
+           fti->type() == KFolderTreeItem::Templates ||
            fti->type() == KFolderTreeItem::SentMail )
         return false;
 
--- kdepim/kmail/kmheaders.cpp.tem	2005-08-09 18:01:12.000000000 +0100
+++ kdepim/kmail/kmheaders.cpp	2005-08-16 16:26:50.000000000 +0100
@@ -651,6 +651,8 @@
     mSortInfo.dirty = true;
     mOwner->editAction()->setEnabled(mFolder ?
         (kmkernel->folderIsDraftOrOutbox(mFolder)): false );
+    mOwner->useAction()->setEnabled(mFolder ?
+        (kmkernel->folderIsTemplates(mFolder)): false );
     mOwner->replyListAction()->setEnabled(mFolder ?
         mFolder->isMailingListEnabled() : false);
     if (mFolder)
@@ -2209,8 +2211,12 @@
   mOwner->updateMessageMenu();
 
   bool out_folder = kmkernel->folderIsDraftOrOutbox(mFolder);
+  bool tem_folder = kmkernel->folderIsTemplates(mFolder);
   if ( out_folder )
      mOwner->editAction()->plug(menu);
+  else if ( tem_folder ) {
+     mOwner->useAction()->plug(menu);
+  }
   else {
      // show most used actions
      mOwner->replyMenu()->plug(menu);
@@ -2241,12 +2247,12 @@
     mOwner->threadStatusMenu()->plug( menu ); // Mark Thread menu
   }
 
-  if (!out_folder && mOwner->watchThreadAction()->isEnabled() ) {
+  if (!out_folder && !tem_folder && mOwner->watchThreadAction()->isEnabled() ) {
     mOwner->watchThreadAction()->plug(menu);
     mOwner->ignoreThreadAction()->plug(menu);
   }
 
-  if ( !out_folder ) {
+  if ( !out_folder && !tem_folder ) {
     menu->insertSeparator();
     mOwner->filterMenu()->plug( menu ); // Create Filter menu
     mOwner->action("apply_filter_actions")->plug(menu);
--- kdepim/kmail/kmkernel.cpp.tem	2005-05-23 13:11:54.000000000 +0100
+++ kdepim/kmail/kmkernel.cpp	2005-08-18 17:20:11.000000000 +0100
@@ -103,6 +103,7 @@
   the_sentFolder = 0;
   the_trashFolder = 0;
   the_draftsFolder = 0;
+  the_templatesFolder = 0;
 
   the_folderMgr = 0;
   the_imapFolderMgr = 0;
@@ -1058,6 +1059,16 @@
   if ( the_draftsFolder->userWhoField().isEmpty() )
     the_draftsFolder->setUserWhoField( QString::null );
   the_draftsFolder->open();
+
+  the_templatesFolder = \
the_folderMgr->findOrCreate(cfg->readEntry("templatesFolder", \
I18N_NOOP("templates"))); +  if (the_templatesFolder->canAccess() != 0) {
+    emergencyExit( i18n("You do not have read/write permission to your templates \
folder.") ); +  }
+  the_templatesFolder->setType("Tf");
+  the_templatesFolder->setSystemFolder(TRUE);
+  if ( the_templatesFolder->userWhoField().isEmpty() )
+    the_templatesFolder->setUserWhoField( QString::null );
+  the_templatesFolder->open();
 }
 
 
@@ -1659,7 +1670,22 @@
   return false;
 }
 
-bool KMKernel::folderIsTrash(KMFolder * folder)
+bool KMKernel::folderIsTemplates(const KMFolder * folder)
+{
+  assert(folder);
+  if (folder == the_templatesFolder) return true;
+
+  QString idString = folder->idString();
+  if ( idString.isEmpty() ) return false;
+
+  // search the identities if the folder matches the templates-folder
+  const KPIM::IdentityManager * im = identityManager();
+  for( KPIM::IdentityManager::ConstIterator it = im->begin(); it != im->end(); ++it \
) +    if ( (*it).templates() == idString ) return true;
+  return false;
+}
+
+bool KMKernel::folderIsTrash(const KMFolder * folder)
 {
   assert(folder);
   if (folder == the_trashFolder) return true;
--- kdepim/kmail/kmkernel.h.tem	2005-05-23 13:11:54.000000000 +0100
+++ kdepim/kmail/kmkernel.h	2005-08-16 14:35:12.000000000 +0100
@@ -177,7 +177,8 @@
   void byteArrayToRemoteFile(const QByteArray&, const KURL&,
 			     bool overwrite = FALSE);
   bool folderIsDraftOrOutbox(const KMFolder *);
-  bool folderIsTrash(KMFolder *);
+  bool folderIsTrash(const KMFolder *);
+  bool folderIsTemplates(const KMFolder *);
   /**
    * Returns true if the folder is one of the sent-mail folders.
    */
@@ -195,6 +196,7 @@
   KMFolder *sentFolder() { return the_sentFolder; }
   KMFolder *trashFolder() { return the_trashFolder; }
   KMFolder *draftsFolder() { return the_draftsFolder; }
+  KMFolder *templatesFolder() { return the_templatesFolder; }
 
   KMFolderMgr *folderMgr() { return the_folderMgr; }
   KMFolderMgr *imapFolderMgr() { return the_imapFolderMgr; }
@@ -337,6 +339,7 @@
   KMFolder *the_sentFolder;
   KMFolder *the_trashFolder;
   KMFolder *the_draftsFolder;
+  KMFolder *the_templatesFolder;
 
   KMFolderMgr *the_folderMgr;
   KMFolderMgr *the_imapFolderMgr;
--- kdepim/kmail/kmmainwidget.cpp.tem	2005-08-09 18:04:39.000000000 +0100
+++ kdepim/kmail/kmmainwidget.cpp	2005-08-20 12:20:44.000000000 +0100
@@ -1287,6 +1287,14 @@
 }
 
 //-----------------------------------------------------------------------------
+void KMMainWidget::slotUseTemplate()
+{
+  kdDebug(0) << k_funcinfo << endl;
+  KMCommand *command = new KMUseTemplateCommand( this, mHeaders->currentMsg() );
+  command->start();
+}
+
+//-----------------------------------------------------------------------------
 void KMMainWidget::slotResendMsg()
 {
   KMCommand *command = new KMResendMessageCommand( this, mHeaders->currentMsg() );
@@ -2041,6 +2049,11 @@
     slotEditMsg();
     return;
   }
+  if (kmkernel->folderIsTemplates(mFolder))
+  {
+    slotUseTemplate();
+    return;
+  }
 
   assert( msg != 0 );
   KMReaderMainWin *win = new KMReaderMainWin( mFolderHtmlPref, \
mFolderHtmlLoadExtPref ); @@ -2122,10 +2135,12 @@
       return;
     }
 
-    bool out_folder = kmkernel->folderIsDraftOrOutbox(mFolder);
-    if ( out_folder ) {
+    if (kmkernel->folderIsDraftOrOutbox(mFolder)) {
       mEditAction->plug(menu);
     }
+    else if (kmkernel->folderIsTemplates(mFolder)) {
+      mUseAction->plug(menu);
+    }
     else {
       mReplyActionMenu->plug(menu);
       mForwardActionMenu->plug(menu);
@@ -2430,6 +2445,9 @@
   mEditAction = new KAction( i18n("&Edit Message"), "edit", Key_T, this,
                             SLOT(slotEditMsg()), actionCollection(), "edit" );
 
+  mUseAction = new KAction( i18n("&Use Template"), "edit", Key_U, this,
+                            SLOT(slotUseTemplate()), actionCollection(), "use" );
+
   //----- "Mark Message" submenu
   mStatusMenu = new KActionMenu ( i18n( "Mar&k Message" ),
                                  actionCollection(), "set_status" );
@@ -2977,8 +2995,8 @@
     forwardMenu()->setEnabled( mass_actions );
 
     bool single_actions = count == 1;
-    mEditAction->setEnabled( single_actions &&
-    kmkernel->folderIsDraftOrOutbox(mFolder));
+    mEditAction->setEnabled( single_actions && \
kmkernel->folderIsDraftOrOutbox(mFolder)); +    mUseAction->setEnabled( \
single_actions && kmkernel->folderIsTemplates(mFolder));  replyMenu()->setEnabled( \
single_actions );  filterMenu()->setEnabled( single_actions );
     replyAction()->setEnabled( single_actions );
--- kdepim/kmail/kmmainwidget.h.tem	2005-05-23 13:11:54.000000000 +0100
+++ kdepim/kmail/kmmainwidget.h	2005-08-20 12:20:53.000000000 +0100
@@ -113,6 +113,7 @@
   KAction *deleteThreadAction() const { return mDeleteThreadAction; }
   KAction *saveAsAction() const { return mSaveAsAction; }
   KAction *editAction() const { return mEditAction; }
+  KAction *useAction() const { return mUseAction; }
   KAction *sendAgainAction() const { return mSendAgainAction; }
   KAction *applyAllFiltersAction() const { return mApplyAllFiltersAction; }
   KAction *findInMessageAction() const { return mFindInMessageAction; }
@@ -257,6 +258,7 @@
   void slotToggleSubjectThreading();
   void slotMessageQueuedOrDrafted();
   void slotEditMsg();
+  void slotUseTemplate();
   //void slotTrashMsg();   // move to trash
   void slotDeleteMsg( bool confirmDelete = true );  // completely delete message
   void slotTrashThread();
@@ -382,7 +384,7 @@
 private:
   // Message actions
   KAction *mTrashAction, *mDeleteAction, *mTrashThreadAction, 
-    *mDeleteThreadAction, *mSaveAsAction, *mEditAction,
+    *mDeleteThreadAction, *mSaveAsAction, *mEditAction, *mUseAction,
     *mSendAgainAction, *mApplyAllFiltersAction, *mFindInMessageAction,
     *mSaveAttachmentsAction, *mOpenAction, *mViewSourceAction;
   // Composition actions
--- kdepim/kmail/kmmessage.cpp.tem	2005-07-20 11:03:02.000000000 +0100
+++ kdepim/kmail/kmmessage.cpp	2005-08-18 16:47:47.000000000 +0100
@@ -179,6 +179,7 @@
   else
     mUnencryptedMsg = 0;
   setDrafts( other.drafts() );
+  setTemplates( other.templates() );
   //mFileName = ""; // we might not want to copy the other messages filename (?)
   //KMMsgBase::assign( &other );
 }
@@ -1553,6 +1554,11 @@
     setDrafts( QString::null );
   else
     setDrafts( ident.drafts() );
+
+  if (ident.templates().isEmpty())
+    setTemplates( QString::null );
+  else
+    setTemplates( ident.templates() );
 }
 
 //-----------------------------------------------------------------------------
@@ -1831,6 +1837,13 @@
 }
 
 //-----------------------------------------------------------------------------
+void KMMessage::setTemplates(const QString& aStr)
+{
+  mTemplates = aStr;
+  kdDebug(5006) << "KMMessage::setTemplates " << aStr << endl;
+}
+
+//-----------------------------------------------------------------------------
 QString KMMessage::who() const
 {
   if (mParent)
--- kdepim/kmail/kmmessage.h.tem	2005-05-23 13:11:54.000000000 +0100
+++ kdepim/kmail/kmmessage.h	2005-08-16 17:20:34.000000000 +0100
@@ -326,6 +326,10 @@
   QString drafts() const { return mDrafts; }
   void setDrafts(const QString& aStr);
 
+  /** Get or set the 'Templates' folder */
+  QString templates() const { return mTemplates; }
+  void setTemplates(const QString& aStr);
+
   /** Get or set the 'From' header field */
   QString from() const;
   void setFrom(const QString& aStr);
@@ -827,6 +831,7 @@
   void assign( const KMMessage& other );
 
   QString mDrafts;
+  QString mTemplates;
   mutable DwMessage* mMsg;
   mutable bool       mNeedsAssembly;
   bool mDecodeHTML;
--- kdepim/kmail/selecttemplatedialog.cpp.tem	2005-08-19 10:05:21.000000000 +0100
+++ kdepim/kmail/selecttemplatedialog.cpp	2005-08-20 13:07:38.000000000 +0100
@@ -0,0 +1,133 @@
+// -*- mode: C++; c-file-style: "gnu" -*-
+// selecttemplatedialog.cpp
+// Author: Jonathan Marten <jjm@keelhaul.demon.co.uk>
+// This code is published under the GPL.
+
+
+#include <klocale.h>
+#include <kdebug.h>
+#include <klistview.h>
+
+#include "kmfolder.h"
+#include "kmmsgbase.h"
+
+#include "selecttemplatedialog.h"
+
+
+static const QString none = i18n("(none)");
+
+
+class SelectTemplateListItem : public QListViewItem
+{
+public:
+  SelectTemplateListItem(QListView *parent,const QString ss,const QString ts = \
QString::null); +  ~SelectTemplateListItem();
+  QString getText() const { return (text); }
+
+private:
+  QString text;
+};
+
+
+SelectTemplateListItem::SelectTemplateListItem(QListView *parent,const QString \
ss,const QString ts) +  : QListViewItem(parent,ss,QString::null)
+{
+  text = ts;
+  if (!text.isNull())
+  {
+    QString dispText = ts;
+    dispText.truncate(80);
+    dispText = dispText.simplifyWhiteSpace();
+
+    int signPos = dispText.find("-- ");
+    if (signPos>1) dispText.truncate(signPos);
+
+    dispText = dispText.stripWhiteSpace();
+    if (dispText.isEmpty()) dispText = none;
+
+    setText(1,dispText);
+  }
+}
+
+
+SelectTemplateListItem::~SelectTemplateListItem()
+{
+}
+
+// -------------------------------------------------------------
+
+SelectTemplateDialog::SelectTemplateDialog(KMFolder *folder,QWidget *parent,const \
char *name) +  : KDialogBase(parent,name,true,i18n("Select \
Template"),KDialogBase::Ok|KDialogBase::Cancel) +{
+  kdDebug(0) << k_funcinfo << "folder=" << ((void*)folder) << endl;
+
+  const bool isImap = (folder->folderType()==KMFolderTypeImap);
+
+  list = new KListView(this);
+  list->setSelectionMode(QListView::Single);
+  list->setShowSortIndicator(true);
+  list->setRootIsDecorated(false);
+
+  list->addColumn(i18n("Subject"),(isImap ? 300 : 150));
+  if (!isImap) list->addColumn(i18n("Text"),200);
+
+  setMainWidget(list);
+  adjustSize();
+  list->setColumnWidth(1,list->columnWidth(1)-1);
+
+  connect(list,SIGNAL(selectionChanged()),this,SLOT(slotListSelectionChanged()));
+  connect(list,SIGNAL(doubleClicked(QListViewItem *,const QPoint &,int)),
+	  this,SLOT(slotListDoubleClicked(QListViewItem *)));
+
+  for (int idx = 0; idx<folder->count(); ++idx)
+  {
+    KMMsgBase *mb = folder->getMsgBase(idx);
+
+    QString subj = mb->subject();
+    if (subj.isEmpty()) subj = none;
+
+    QString text = QString::null;
+    if (!isImap)
+    {
+      bool wasmsg = mb->isMessage();
+      KMMessage *msg = (!wasmsg ? folder->getMsg(idx) : static_cast<KMMessage \
*>(mb)); +      text = msg->bodyToUnicode();
+      if (!wasmsg) folder->unGetMsg(idx);
+    }
+    (void) new SelectTemplateListItem(list,subj,text);
+  }
+
+  slotListSelectionChanged();
+  kdDebug(0) << k_funcinfo << "done" << endl;
+}
+
+
+SelectTemplateDialog::~SelectTemplateDialog()
+{
+}
+
+
+void SelectTemplateDialog::slotListDoubleClicked(QListViewItem *item)
+{
+  if (item==NULL) return;
+  list->setSelected(item,true);
+  slotOk();
+}
+
+
+void SelectTemplateDialog::slotListSelectionChanged()
+{
+  enableButtonOK(list->selectedItem()!=NULL);
+}
+
+
+QString SelectTemplateDialog::selectedTemplateText()
+{
+  // TODO: if an IMAP folder, need to retrieve the message at this stage
+  // then get the text from it
+  SelectTemplateListItem *item = static_cast<SelectTemplateListItem \
*>(list->selectedItem()); +  return (item!=NULL ? item->getText() : QString::null);
+}
+
+
+#include "selecttemplatedialog.moc"
--- kdepim/kmail/selecttemplatedialog.h.tem	2005-08-19 10:05:23.000000000 +0100
+++ kdepim/kmail/selecttemplatedialog.h	2005-08-20 13:02:25.000000000 +0100
@@ -0,0 +1,40 @@
+/* -*- mode: C++ -*-
+ *
+ * Dialogue box to list and select a template.
+ *
+ * Author: Jonathan Marten <jjm@keelhaul.demon.co.uk>
+ * This code is under GPL
+ *
+ */
+
+#ifndef selecttemplatedialog_h
+#define selecttemplatedialog_h
+
+#include <qstring.h>
+
+#include <kdialogbase.h>
+
+class QWidget;
+class KMFolder;
+class KListView;
+
+class SelectTemplateDialog : public KDialogBase
+{
+	Q_OBJECT
+
+public:
+	SelectTemplateDialog(KMFolder *folder, QWidget *parent = NULL, const char *name = \
NULL); +	~SelectTemplateDialog();
+
+	/** Get the text to be inserted from the selected template */
+	QString selectedTemplateText();
+
+protected slots:
+	void slotListSelectionChanged();
+	void slotListDoubleClicked(QListViewItem *item);
+
+private:
+	KListView *list;
+};
+
+#endif /* selecttemplatedialog_h */
--- kdepim/libkdepim/kfoldertree.cpp.tem	2005-05-23 13:12:29.000000000 +0100
+++ kdepim/libkdepim/kfoldertree.cpp	2005-08-16 15:05:36.000000000 +0100
@@ -65,14 +65,16 @@
     return 4;
   case Drafts:
     return 5;
-  case Calendar:
+  case Templates:
     return 6;
-  case Contacts:
+  case Calendar:
     return 7;
-  case Notes:
+  case Contacts:
     return 8;
-  case Tasks:
+  case Notes:
     return 9;
+  case Tasks:
+    return 10;
   default:
     return 42;
   }
--- kdepim/libkpimidentities/identity.cpp.tem	2005-05-23 13:12:15.000000000 +0100
+++ kdepim/libkpimidentities/identity.cpp	2005-08-18 16:55:49.000000000 +0100
@@ -232,7 +232,7 @@
   return mIdentity.isEmpty() && mFullName.isEmpty() && mEmailAddr.isEmpty() &&
     mOrganization.isEmpty() && mReplyToAddr.isEmpty() && mBcc.isEmpty() &&
     mVCardFile.isEmpty() &&
-    mFcc.isEmpty() && mDrafts.isEmpty() &&
+    mFcc.isEmpty() && mDrafts.isEmpty() && mTemplates.isEmpty() &&
     mPGPEncryptionKey.isEmpty() && mPGPSigningKey.isEmpty() &&
     mSMIMEEncryptionKey.isEmpty() && mSMIMESigningKey.isEmpty() &&
     mTransport.isEmpty() && mDictionary.isEmpty() &&
@@ -253,7 +253,7 @@
       mSMIMEEncryptionKey == other.mSMIMEEncryptionKey &&
       mSMIMESigningKey == other.mSMIMESigningKey &&
       mPreferredCryptoMessageFormat == other.mPreferredCryptoMessageFormat &&
-      mDrafts == other.mDrafts && mTransport == other.mTransport &&
+      mDrafts == other.mDrafts && mTemplates == other.mTemplates && mTransport == \
                other.mTransport &&
       mDictionary == other.mDictionary && mSignature == other.mSignature &&
       mXFace == other.mXFace && mXFaceEnabled == other.mXFaceEnabled;
 
@@ -275,6 +275,7 @@
   if ( mSMIMESigningKey != other.mSMIMESigningKey ) kdDebug() << "mSMIMESigningKey \
differs : " << mSMIMESigningKey << " != " << other.mSMIMESigningKey << endl;  if ( \
mPreferredCryptoMessageFormat != other.mPreferredCryptoMessageFormat ) kdDebug() << \
"mPreferredCryptoMessageFormat differs : " << mPreferredCryptoMessageFormat << " != " \
<< other.mPreferredCryptoMessageFormat << endl;  if ( mDrafts != other.mDrafts ) \
kdDebug() << "mDrafts differs : " << mDrafts << " != " << other.mDrafts << endl; +  \
if ( mTemplates != other.mTemplatess ) kdDebug() << "mTemplates differs : " << \
mTemplates << " != " << other.mTemplates << endl;  if ( mTransport != \
other.mTransport ) kdDebug() << "mTransport differs : " << mTransport << " != " << \
other.mTransport << endl;  if ( mDictionary != other.mDictionary ) kdDebug() << \
"mDictionary differs : " << mDictionary << " != " << other.mDictionary << endl;  if ( \
! ( mSignature == other.mSignature ) ) kdDebug() << "mSignature differs" << endl; @@ \
-291,7 +292,8 @@  // Using "" instead of null to make operator==() not fail
     // (readConfig returns "")
     mBcc( "" ), mVCardFile( "" ), mPGPEncryptionKey( "" ), mPGPSigningKey( "" ),
-    mSMIMEEncryptionKey( "" ), mSMIMESigningKey( "" ), mFcc( "" ), mDrafts( "" ), \
mTransport( "" ), +    mSMIMEEncryptionKey( "" ), mSMIMESigningKey( "" ), mFcc( "" ),
+    mDrafts( "" ), mTemplates( "" ), mTransport( "" ),
     mDictionary( "" ),
     mXFace( "" ), mXFaceEnabled( false ),
     mIsDefault( false ),
@@ -326,6 +328,9 @@
   mDrafts = config->readEntry("Drafts", "drafts");
   if( mDrafts.isEmpty() )
     mDrafts = "drafts";
+  mTemplates = config->readEntry("Templates", "templates");
+  if( mTemplates.isEmpty() )
+    mTemplates = "templates";
   mTransport = config->readEntry("Transport");
   mDictionary = config->readEntry( "Dictionary" );
   mXFace = config->readEntry( "X-Face" );
@@ -356,6 +361,7 @@
   config->writeEntry("Transport", mTransport);
   config->writeEntry("Fcc", mFcc);
   config->writeEntry("Drafts", mDrafts);
+  config->writeEntry("Templates", mTemplates);
   config->writeEntry( "Dictionary", mDictionary );
   config->writeEntry( "X-Face", mXFace );
   config->writeEntry( "X-FaceEnabled", mXFaceEnabled );
@@ -379,6 +385,7 @@
 		<< i.transport()
 		<< i.fcc()
 		<< i.drafts()
+		<< i.templates()
 		<< i.mSignature
                 << i.dictionary()
                 << i.xface()
@@ -403,6 +410,7 @@
 		>> i.mTransport
 		>> i.mFcc
 		>> i.mDrafts
+		>> i.mTemplates
 		>> i.mSignature
                 >> i.mDictionary
                 >> i.mXFace
@@ -560,6 +568,15 @@
 
 
 //-----------------------------------------------------------------------------
+void Identity::setTemplates(const QString &str)
+{
+  mTemplates = str;
+  if ( mTemplates.isNull() )
+    mTemplates = "";
+}
+
+
+//-----------------------------------------------------------------------------
 void Identity::setDictionary( const QString &str )
 {
   mDictionary = str;
--- kdepim/libkpimidentities/identity.h.tem	2005-05-23 13:12:15.000000000 +0100
+++ kdepim/libkpimidentities/identity.h	2005-08-18 16:56:27.000000000 +0100
@@ -269,6 +269,11 @@
   QString drafts() const { return mDrafts; }
   void setDrafts(const QString&);
 
+  /** The folder where template messages for this identity will be
+      stored by default. */
+  QString templates() const { return mTemplates; }
+  void setTemplates(const QString&);
+
   /** dictionary which should be used for spell checking */
   QString dictionary() const { return mDictionary; }
   void setDictionary( const QString& );
@@ -292,7 +297,7 @@
   QString mBcc;
   QString mVCardFile;
   QCString mPGPEncryptionKey, mPGPSigningKey, mSMIMEEncryptionKey, mSMIMESigningKey;
-  QString mFcc, mDrafts, mTransport;
+  QString mFcc, mDrafts, mTemplates, mTransport;
   QString mDictionary;
   QString mXFace;
   bool mXFaceEnabled;
---patch ends -----------------------------------------------------------

-- 
Jonathan Marten                           work:  currently looking
http://www.keelhaul.demon.co.uk/          play:  jjm@keelhaul.demon.co.uk
_______________________________________________
KMail developers mailing list
KMail-devel@kde.org
https://mail.kde.org/mailman/listinfo/kmail-devel


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic