[dasher] Move trainfile buffer into AlphabetManager & update learn-as-you-write...



commit 6219110bf12fb2c8885ff6ea7543eef0dba71395
Author: Alan Lawrence <acl33 inf phy cam ac uk>
Date:   Thu Mar 3 16:16:13 2011 +0000

    Move trainfile buffer into AlphabetManager & update learn-as-you-write...
    
    CDasherInterfaceBase::WriteTrainFileFull() calls to AlphMgr, calls back to
    DashIntf::WriteTrainFile() w/ fname (from alphabet => GC SP_TRAIN_FILE) + text
    
    CAlphNode::SetFlag(NF_COMMITTED,xxx) tests if flag changing, tries to get parent
      node ctx (=> RM AlphMgr::iLearnContext), fails & preserves flag if can't
      (Should behave better in face of cursor movement, root reparenting, etc.)
    DasherModel delays clearing NF_COMMITTED until Undo() to avoid repeat training
    
    Text appended to buffer in CSymbolNode::Output(/Undo), so different from what is
      fed to LM when node committed.

 Src/DasherCore/AlphabetManager.cpp           |   44 +++++++++++++++++++-------
 Src/DasherCore/AlphabetManager.h             |    9 +++--
 Src/DasherCore/DasherInterfaceBase.cpp       |   15 ++------
 Src/DasherCore/DasherInterfaceBase.h         |   25 ++++++--------
 Src/DasherCore/DasherModel.cpp               |    8 ++++-
 Src/DasherCore/MandarinAlphMgr.cpp           |    7 ++--
 Src/DasherCore/NodeCreationManager.cpp       |    1 -
 Src/DasherCore/Parameters.h                  |    3 +-
 Src/Gtk2/DasherControl.cpp                   |    4 +-
 Src/Gtk2/DasherControl.h                     |    5 ++-
 Src/MacOSX/COSXDasherControl.h               |    2 +-
 Src/MacOSX/COSXDasherControl.mm              |    4 +-
 Src/Win32/Dasher.cpp                         |    6 ++--
 Src/Win32/Dasher.h                           |    2 +-
 Src/iPhone/Classes/CDasherInterfaceBridge.h  |    2 +-
 Src/iPhone/Classes/CDasherInterfaceBridge.mm |    4 +-
 16 files changed, 79 insertions(+), 62 deletions(-)
---
diff --git a/Src/DasherCore/AlphabetManager.cpp b/Src/DasherCore/AlphabetManager.cpp
index 91af931..2e0c04c 100644
--- a/Src/DasherCore/AlphabetManager.cpp
+++ b/Src/DasherCore/AlphabetManager.cpp
@@ -73,8 +73,6 @@ void CAlphabetManager::CreateLanguageModel(CEventHandler *pEventHandler, CSettin
       m_pLanguageModel = new CCTWLanguageModel(m_pAlphabet->GetNumberTextSymbols());
       break;
   }
-  
-  m_iLearnContext = m_pLanguageModel->CreateEmptyContext();
 }
 
 CTrainer *CAlphabetManager::GetTrainer() {
@@ -86,12 +84,16 @@ const CAlphInfo *CAlphabetManager::GetAlphabet() const {
 }
 
 CAlphabetManager::~CAlphabetManager() {
-  m_pLanguageModel->ReleaseContext(m_iLearnContext);
   //the alphabet belongs to the AlphIO, and may be reused later;
   delete m_pAlphabetMap; //the map was created for this mgr.
   delete m_pLanguageModel;
 }
 
+void CAlphabetManager::WriteTrainFileFull(CDasherInterfaceBase *pInterface) {
+  pInterface->WriteTrainFile(m_pAlphabet->GetTrainingFile(), strTrainfileBuffer);
+  strTrainfileBuffer="";
+}
+
 int CAlphabetManager::GetColour(symbol sym, int iOffset) const {
   int iColour = m_pAlphabet->GetColour(sym);
   
@@ -150,11 +152,10 @@ CAlphabetManager::CAlphNode *CAlphabetManager::GetRoot(CDasherNode *pParent, uns
     //couldn't extract last symbol (so probably using default context), or shouldn't
     pNewNode = new CGroupNode(pParent, iNewOffset, iLower, iUpper, "", 0, this, NULL); //default background colour
   } else {
+    //new node represents a symbol that's already happened - i.e. user has already steered through it;
+    // so either we're rebuilding, or else creating a new root from existing text (in edit box)
+    DASHER_ASSERT(!pParent);
     pNewNode = new CSymbolNode(pParent, iNewOffset, iLower, iUpper, "", this, p.first);
-    //if the new node is not child of an existing node, then it
-    // represents a symbol that's already happened - so we're either
-    // going backwards (rebuildParent) or creating a new root after a language change
-    DASHER_ASSERT (!pParent);
   }
 
   pNewNode->iContext = p.second;
@@ -498,6 +499,8 @@ void CAlphabetManager::CSymbolNode::Output(Dasher::VECTOR_SYMBOL_PROB* pAdded, i
   if (pAdded != NULL) {
     pAdded->push_back(Dasher::SymbolProb(iSymbol, outputText(), Range() / (double)iNormalization));
   }
+  if(m_pMgr->m_pNCManager->GetBoolParameter(BP_LM_ADAPTIVE))
+    m_pMgr->strTrainfileBuffer += oEvent.m_sText;
 }
 
 void CAlphabetManager::CSymbolNode::Undo(int *pNumDeleted) {
@@ -505,6 +508,9 @@ void CAlphabetManager::CSymbolNode::Undo(int *pNumDeleted) {
   Dasher::CEditEvent oEvent(2, outputText(), offset());
   m_pMgr->m_pNCManager->InsertEvent(&oEvent);
   if (pNumDeleted) (*pNumDeleted)++;
+  if(m_pMgr->m_pNCManager->GetBoolParameter(BP_LM_ADAPTIVE))
+    m_pMgr->strTrainfileBuffer = m_pMgr->strTrainfileBuffer.substr( 0, m_pMgr->strTrainfileBuffer.size() - oEvent.m_sText.size());
+  
 }
 
 CDasherNode *CAlphabetManager::CGroupNode::RebuildParent() {
@@ -527,8 +533,8 @@ CDasherNode *CAlphabetManager::CAlphBase::RebuildParent() {
     
     RebuildForwardsFromAncestor(pNewNode);
     
-    if (GetFlag(NF_SEEN)) {
-      for (CDasherNode *pNode=this; (pNode=pNode->Parent()); pNode->SetFlag(NF_SEEN, true));
+    if (int flags=(GetFlag(NF_SEEN) ? NF_SEEN : 0) | (GetFlag(NF_COMMITTED) ? NF_COMMITTED : 0)) {
+      for (CDasherNode *pNode=this; (pNode=pNode->Parent()); pNode->SetFlag(flags, true));
     }
   }
   return Parent();
@@ -542,9 +548,23 @@ void CAlphabetManager::CAlphBase::RebuildForwardsFromAncestor(CAlphNode *pNewNod
 // TODO: Shouldn't there be an option whether or not to learn as we write?
 // For want of a better solution, game mode exemption explicit in this function
 void CAlphabetManager::CSymbolNode::SetFlag(int iFlag, bool bValue) {
-  if (iFlag==NF_COMMITTED && bValue && !GetFlag(NF_COMMITTED)
-      && !GetFlag(NF_GAME) && m_pMgr->m_pInterface->GetBoolParameter(BP_LM_ADAPTIVE)) {
-      m_pMgr->m_pLanguageModel->LearnSymbol(m_pMgr->m_iLearnContext, iSymbol);
+  if ((iFlag & NF_COMMITTED) && bValue && !GetFlag(NF_COMMITTED | NF_GAME)
+      && m_pMgr->m_pInterface->GetBoolParameter(BP_LM_ADAPTIVE)) {
+    //try to commit...if we have parent (else rebuilding (backwards) => don't)
+    if (Parent()) {
+      if (Parent()->mgr() != mgr()) return; //do not set flag
+      CLanguageModel *pLM(m_pMgr->m_pLanguageModel);
+      // (Note: for first symbol after startup: parent is (root) group node, which'll have the alphabet default context) 
+      CLanguageModel::Context ctx = pLM->CloneContext(static_cast<CAlphabetManager::CAlphNode *>(Parent())->iContext);
+      pLM->LearnSymbol(ctx, iSymbol);
+      //could: pLM->ReleaseContext(ctx);
+      //however, seems better to replace this node's context (i.e. which it uses to create its own children)
+      // with the new (learned) context: the former was obtained by EnterSymbol rather than LearnSymbol, so
+      // will be different iff this node was the first time its symbol was entered into its parent context.
+      // (Yes, this node's context is unlikely to be used again, but not impossible...)
+      pLM->ReleaseContext(iContext);
+      iContext = ctx;
+    }
   }
   CDasherNode::SetFlag(iFlag, bValue);
 }
diff --git a/Src/DasherCore/AlphabetManager.h b/Src/DasherCore/AlphabetManager.h
index 5d386a2..daf59f1 100644
--- a/Src/DasherCore/AlphabetManager.h
+++ b/Src/DasherCore/AlphabetManager.h
@@ -57,7 +57,9 @@ namespace Dasher {
     virtual CTrainer *GetTrainer();
 
     virtual ~CAlphabetManager();
-
+    /// Flush to the user's training file everything written in this AlphMgr
+    /// \param pInterface to use for I/O by calling WriteTrainFile(fname,txt)
+    void WriteTrainFileFull(CDasherInterfaceBase *pInterface);
   protected:
     class CAlphNode;
     /// Abstract superclass for alphabet manager nodes, provides common implementation
@@ -215,7 +217,6 @@ namespace Dasher {
     virtual int GetColour(symbol sym, int iOffset) const;
     
     CLanguageModel *m_pLanguageModel;
-    CLanguageModel::Context m_iLearnContext;
 
     CNodeCreationManager *m_pNCManager;
     const CAlphInfo *m_pAlphabet;
@@ -237,7 +238,9 @@ namespace Dasher {
     void IterateChildGroups(CAlphNode *pParent, const SGroupInfo *pParentGroup, CAlphBase *buildAround);
 
     CDasherInterfaceBase *m_pInterface;
-    
+    ///Text waiting to be written to the user's training file
+    /// (probably! Unless they erase back out of the text first)
+    std::string strTrainfileBuffer;
   };
 /// @}
 
diff --git a/Src/DasherCore/DasherInterfaceBase.cpp b/Src/DasherCore/DasherInterfaceBase.cpp
index c13d9d3..68ee06e 100644
--- a/Src/DasherCore/DasherInterfaceBase.cpp
+++ b/Src/DasherCore/DasherInterfaceBase.cpp
@@ -105,8 +105,6 @@ CDasherInterfaceBase::CDasherInterfaceBase() {
 
   //  m_bGlobalLock = false;
 
-  strTrainfileBuffer = "";
-
   m_strCurrentWord = "";
 
   // Create an event handler.
@@ -341,8 +339,6 @@ void CDasherInterfaceBase::InterfaceEventHandler(Dasher::CEvent *pEvent) {
     CEditEvent *pEditEvent(static_cast < CEditEvent * >(pEvent));
 
     if(pEditEvent->m_iEditType == 1) {
-      if(GetBoolParameter(BP_LM_ADAPTIVE))
-	 strTrainfileBuffer += pEditEvent->m_sText;
       if (GetBoolParameter(BP_SPEAK_WORDS) && SupportsSpeech()) {
         const CAlphInfo *pAlphabet = m_pNCManager->GetAlphabet();
         if (pEditEvent->m_sText == pAlphabet->GetText(pAlphabet->GetSpaceSymbol())) {
@@ -353,8 +349,6 @@ void CDasherInterfaceBase::InterfaceEventHandler(Dasher::CEvent *pEvent) {
       }
     }
     else if(pEditEvent->m_iEditType == 2) {
-      if(GetBoolParameter(BP_LM_ADAPTIVE))
-	 strTrainfileBuffer = strTrainfileBuffer.substr( 0, strTrainfileBuffer.size() - pEditEvent->m_sText.size());
       if (GetBoolParameter(BP_SPEAK_WORDS))
         m_strCurrentWord = m_strCurrentWord.substr(0, max(static_cast<string::size_type>(0), m_strCurrentWord.size()-pEditEvent->m_sText.size()));
     }
@@ -362,8 +356,7 @@ void CDasherInterfaceBase::InterfaceEventHandler(Dasher::CEvent *pEvent) {
 }
 
 void CDasherInterfaceBase::WriteTrainFileFull() {
-  WriteTrainFile(strTrainfileBuffer);
-  strTrainfileBuffer = "";
+  m_pNCManager->GetAlphabetManager()->WriteTrainFileFull(this);
 }
 
 void CDasherInterfaceBase::CreateNCManager() {
@@ -591,10 +584,10 @@ void CDasherInterfaceBase::ChangeAlphabet() {
     return;
   }
 
-  // Send a lock event
-
-  WriteTrainFileFull();
+  if (m_pNCManager) WriteTrainFileFull(); //can't/don't before creating first NCManager
 
+  // Send a lock event
+  
   // Lock Dasher to prevent changes from happening while we're training.
 
   SetBoolParameter( BP_TRAINING, true );
diff --git a/Src/DasherCore/DasherInterfaceBase.h b/Src/DasherCore/DasherInterfaceBase.h
index 62f3215..dfd9f64 100644
--- a/Src/DasherCore/DasherInterfaceBase.h
+++ b/Src/DasherCore/DasherInterfaceBase.h
@@ -255,6 +255,14 @@ public:
   virtual bool hasStopTriggers();
   /// @}
 
+  ///
+  /// Append text to the user training file - used to store state between sessions
+  /// \param filename name of training file, without path (e.g. "training_english_GB.txt")
+  /// \param strNewText text to append
+  ///
+  
+  virtual void WriteTrainFile(const std::string &filename, const std::string &strNewText) {
+  };
 
   // App Interface
   // -----------------------------------------------------
@@ -398,8 +406,9 @@ public:
 
   void ImportTrainingText(const std::string &strPath);
   
-  ///Making this public for e.g. iPhone, which needs to flush
-  /// the trainfile buffer when app is sent into background.
+  /// Flush the/all currently-written text to the user's training file(s).
+  /// Just calls through to WriteTrainFileFull(this) on the AlphabetManager;
+  /// public so e.g. iPhone can flush the buffer when app is backgrounded.
   void WriteTrainFileFull();
   
 protected:
@@ -539,15 +548,6 @@ protected:
 
   virtual void ShutdownTimer() = 0;
 
-  ///
-  /// Append text to the training file - used to store state between
-  /// sessions
-  /// @todo Pass file path to the function rather than having implementations work it out themselves
-  ///
-  
-  virtual void WriteTrainFile(const std::string &strNewText) {
-  };
-
   /// @}
 
 
@@ -589,9 +589,6 @@ protected:
   CNodeCreationManager *m_pNCManager;
   CUserLogBase *m_pUserLog; 
   /// @}
-
-  ///TODO this is in the wrong place. DashIntf should not be managing the training file...
-  std::string strTrainfileBuffer;
   
   ///builds up the word currently being entered for speech.
   std::string m_strCurrentWord;
diff --git a/Src/DasherCore/DasherModel.cpp b/Src/DasherCore/DasherModel.cpp
index d703d72..f603d39 100644
--- a/Src/DasherCore/DasherModel.cpp
+++ b/Src/DasherCore/DasherModel.cpp
@@ -201,7 +201,8 @@ bool CDasherModel::Reparent_root() {
     return false;
   }
   
-  pNewRoot->SetFlag(NF_COMMITTED, false);
+  //don't uncommit until they reverse out of the node
+  // (or committing would enter the node into the LM a second time)
   
   //Update the root coordinates to reflect the new root
   DASHER_ASSERT(pNewRoot->GetFlag(NF_SEEN));
@@ -251,6 +252,10 @@ void CDasherModel::SetOffset(int iOffset, CAlphabetManager *pMgr, CDasherView *p
     m_Root->Enter();
     // (of course, we don't do Output() - the context contains it already!)
     m_pLastOutput = m_Root;
+    
+    //We also want to avoid training the LM on nodes representing already-written context
+    m_Root->SetFlag(NF_COMMITTED, true);
+    
   } else
     m_pLastOutput = NULL;
   
@@ -505,6 +510,7 @@ void CDasherModel::OutputTo(CDasherNode *pNewNode, Dasher::VECTOR_SYMBOL_PROB* p
     while (m_pLastOutput != pNewNode) {
       // if pNewNode is null, m_pLastOutput is not; else, pNewNode has been seen,
       // so we should encounter it on the way back out to the root, _before_ null
+      m_pLastOutput->SetFlag(NF_COMMITTED, false);
       m_pLastOutput->Undo(pNumDeleted);
       m_pLastOutput->Leave(); //Should we? I think so, but the old code didn't...?
       m_pLastOutput->SetFlag(NF_SEEN, false);
diff --git a/Src/DasherCore/MandarinAlphMgr.cpp b/Src/DasherCore/MandarinAlphMgr.cpp
index a387a9d..574fce8 100644
--- a/Src/DasherCore/MandarinAlphMgr.cpp
+++ b/Src/DasherCore/MandarinAlphMgr.cpp
@@ -120,9 +120,6 @@ void CMandarinAlphMgr::CreateLanguageModel(CEventHandler *pEventHandler, CSettin
   //std::cout<<"CHALphabet size "<< pCHAlphabet->GetNumberTextSymbols(); [7603]
   std::cout<<"Setting PPMPY model"<<std::endl;
   m_pLanguageModel = new CPPMPYLanguageModel(pEventHandler, pSettingsStore, m_CHtext.size()-1, m_pAlphabet->GetNumberTextSymbols());
-  //our superclass destructor will call ReleaseContext on the iLearnContext when we are destroyed,
-  // so we need to put _something_ in there (even tho we don't use it atm!)...
-  m_iLearnContext = m_pLanguageModel->CreateEmptyContext();
 }
 
 CTrainer *CMandarinAlphMgr::GetTrainer() {
@@ -252,7 +249,9 @@ bool CMandarinAlphMgr::CConvRoot::isInGroup(const SGroupInfo *pGroup) {
 void CMandarinAlphMgr::CConvRoot::SetFlag(int iFlag, bool bValue) {
   if (iFlag==NF_COMMITTED && bValue && !GetFlag(NF_COMMITTED)
       && !GetFlag(NF_GAME) && mgr()->m_pNCManager->GetBoolParameter(BP_LM_ADAPTIVE)) {
-    static_cast<CPPMPYLanguageModel *>(mgr()->m_pLanguageModel)->LearnPYSymbol(mgr()->m_iLearnContext, m_pySym);
+    //CConvRoot's context is the same as parent's context (no symbol yet!),
+    // i.e. is the context in which the pinyin was predicted.
+    static_cast<CPPMPYLanguageModel *>(mgr()->m_pLanguageModel)->LearnPYSymbol(iContext, m_pySym);
   }
   CDasherNode::SetFlag(iFlag,bValue);
 }
diff --git a/Src/DasherCore/NodeCreationManager.cpp b/Src/DasherCore/NodeCreationManager.cpp
index 6b9f20d..725ddf6 100644
--- a/Src/DasherCore/NodeCreationManager.cpp
+++ b/Src/DasherCore/NodeCreationManager.cpp
@@ -17,7 +17,6 @@ CNodeCreationManager::CNodeCreationManager(Dasher::CDasherInterfaceBase *pInterf
   const Dasher::CAlphInfo *pAlphInfo(pAlphIO->GetInfo(pSettingsStore->GetStringParameter(SP_ALPHABET_ID)));
   const CAlphabetMap *pAlphMap = pAlphInfo->MakeMap();
   
-  pSettingsStore->SetStringParameter(SP_TRAIN_FILE, pAlphInfo->GetTrainingFile());
   pSettingsStore->SetStringParameter(SP_GAME_TEXT_FILE, pAlphInfo->GetGameModeFile());
   
   pSettingsStore->SetStringParameter(SP_DEFAULT_COLOUR_ID, pAlphInfo->GetPalette());
diff --git a/Src/DasherCore/Parameters.h b/Src/DasherCore/Parameters.h
index 6e2cf17..5484b36 100644
--- a/Src/DasherCore/Parameters.h
+++ b/Src/DasherCore/Parameters.h
@@ -74,7 +74,7 @@ enum {
 enum {
   SP_ALPHABET_ID = END_OF_LPS, SP_ALPHABET_1, SP_ALPHABET_2, SP_ALPHABET_3, SP_ALPHABET_4, 
   SP_COLOUR_ID, SP_DEFAULT_COLOUR_ID, SP_DASHER_FONT, SP_SYSTEM_LOC, SP_USER_LOC, SP_GAME_TEXT_FILE,
-  SP_TRAIN_FILE, SP_SOCKET_INPUT_X_LABEL, SP_SOCKET_INPUT_Y_LABEL, SP_INPUT_FILTER, SP_INPUT_DEVICE,
+  SP_SOCKET_INPUT_X_LABEL, SP_SOCKET_INPUT_Y_LABEL, SP_INPUT_FILTER, SP_INPUT_DEVICE,
   SP_BUTTON_0, SP_BUTTON_1, SP_BUTTON_2, SP_BUTTON_3, SP_BUTTON_4, SP_BUTTON_10, SP_JOYSTICK_DEVICE,
 #ifdef TARGET_OS_IPHONE
   SP_CUSTOM_TILT, SP_VERTICAL_TILT,
@@ -286,7 +286,6 @@ static sp_table stringparamtable[] = {
   {SP_SYSTEM_LOC, "SystemLocation", !PERS, "sys_", "System Directory"},
   {SP_USER_LOC, "UserLocation", !PERS, "usr_", "User Directory"},
   {SP_GAME_TEXT_FILE, "GameTextFile", !PERS, "", "File with strings to practice writing"},
-  {SP_TRAIN_FILE, "TrainingFile", !PERS, "", "Training text for alphabet"},
   {SP_SOCKET_INPUT_X_LABEL, "SocketInputXLabel", PERS, "x", "Label preceding X values for network input"},
   {SP_SOCKET_INPUT_Y_LABEL, "SocketInputYLabel", PERS, "y", "Label preceding Y values for network input"},
 #if defined(WITH_MAEMO) || defined(TARGET_OS_IPHONE)
diff --git a/Src/Gtk2/DasherControl.cpp b/Src/Gtk2/DasherControl.cpp
index 45cda0f..942aa0b 100644
--- a/Src/Gtk2/DasherControl.cpp
+++ b/Src/Gtk2/DasherControl.cpp
@@ -382,11 +382,11 @@ void CDasherControl::ExecuteCommand(const std::string &strCommand) {
     g_signal_emit_by_name(GTK_WIDGET(m_pDasherControl), "dasher_command", strCommand.c_str());
 }
 
-void CDasherControl::WriteTrainFile(const std::string &strNewText) {
+void CDasherControl::WriteTrainFile(const std::string &filename, const std::string &strNewText) {
   if(strNewText.length() == 0)
     return;
 
-  std::string strFilename(GetStringParameter(SP_USER_LOC) + GetStringParameter(SP_TRAIN_FILE));
+  std::string strFilename(GetStringParameter(SP_USER_LOC) + filename);
 
   int fd=open(strFilename.c_str(),O_CREAT|O_WRONLY|O_APPEND,S_IRUSR|S_IWUSR);
   write(fd,strNewText.c_str(),strNewText.length());
diff --git a/Src/Gtk2/DasherControl.h b/Src/Gtk2/DasherControl.h
index c91d19a..28e9ab9 100644
--- a/Src/Gtk2/DasherControl.h
+++ b/Src/Gtk2/DasherControl.h
@@ -134,7 +134,9 @@ public:
 
   ///Override to broadcast signal...
   virtual void Stop();
-  
+ 
+  virtual void WriteTrainFile(const std::string &filename, const std::string &strNewText);
+ 
   virtual std::string GetAllContext();
 
   virtual bool SupportsClipboard();
@@ -155,7 +157,6 @@ private:
   virtual void SetupUI();
   virtual void CreateSettingsStore();
   virtual int GetFileSize(const std::string &strFileName);
-  virtual void WriteTrainFile(const std::string &strNewText);
   virtual void StartTimer();
   virtual void ShutdownTimer();
 
diff --git a/Src/MacOSX/COSXDasherControl.h b/Src/MacOSX/COSXDasherControl.h
index b47a845..b2a8e65 100644
--- a/Src/MacOSX/COSXDasherControl.h
+++ b/Src/MacOSX/COSXDasherControl.h
@@ -45,6 +45,7 @@ public:
   void SetParameter(NSString *aKey, id aValue);
   NSDictionary *ParameterDictionary();
   void goddamn(unsigned long iTime, bool bForceRedraw);
+  virtual void WriteTrainFile(const std::string &filename, const std::string &strNewText);
   std::string GetAllContext();
   void ClearAllContext();
   
@@ -56,7 +57,6 @@ private:
   virtual void SetupUI();
   virtual void CreateSettingsStore();
   virtual int GetFileSize(const std::string &strFileName);
-  virtual void WriteTrainFile(const std::string &strNewText);
   virtual void StartTimer();
   virtual void ShutdownTimer();
   virtual bool SupportsSpeech();
diff --git a/Src/MacOSX/COSXDasherControl.mm b/Src/MacOSX/COSXDasherControl.mm
index b2d7a77..96f1ea3 100644
--- a/Src/MacOSX/COSXDasherControl.mm
+++ b/Src/MacOSX/COSXDasherControl.mm
@@ -222,11 +222,11 @@ void COSXDasherControl::Train(NSString *fileName) {
   CDasherInterfaceBase::ImportTrainingText(f);
 }
 
-void COSXDasherControl::WriteTrainFile(const std::string &strNewText) {
+void COSXDasherControl::WriteTrainFile(const std::string &filename, const std::string &strNewText) {
   if(strNewText.length() == 0)
     return;
   
-  std::string strFilename(GetStringParameter(SP_USER_LOC) + GetStringParameter(SP_TRAIN_FILE));
+  std::string strFilename(GetStringParameter(SP_USER_LOC) + filename);
   
   NSLog(@"Write train file: %s", strFilename.c_str());
   
diff --git a/Src/Win32/Dasher.cpp b/Src/Win32/Dasher.cpp
index 570d0e8..31e127d 100644
--- a/Src/Win32/Dasher.cpp
+++ b/Src/Win32/Dasher.cpp
@@ -143,8 +143,8 @@ void Dasher::CDasher::SetEdit(CDashEditbox * pEdit) {
   m_pEdit = pEdit;
 }
 
-void Dasher::CDasher::WriteTrainFile(const std::string &strNewText) {
-  const std::string TrainFile = GetStringParameter(SP_USER_LOC) + GetStringParameter(SP_TRAIN_FILE);
+void Dasher::CDasher::WriteTrainFile(const std::string &filename, const std::string &strNewText) {
+  const std::string TrainFile = GetStringParameter(SP_USER_LOC) + filename;
 
   if(strNewText.size() == 0)
     return;
@@ -360,4 +360,4 @@ std::string CDasher::GetAllContext() {
 	LPTSTR allspeech = new TCHAR[speechlength + 1];
 	m_pEdit->GetWindowText(allspeech, speechlength + 1);
     return allspeech;
-}
\ No newline at end of file
+}
diff --git a/Src/Win32/Dasher.h b/Src/Win32/Dasher.h
index ba93a1d..7659972 100644
--- a/Src/Win32/Dasher.h
+++ b/Src/Win32/Dasher.h
@@ -46,7 +46,7 @@ public:
   void ExternalEventHandler(Dasher::CEvent *pEvent);
   void GameMessageOut(int message, const void* messagedata);
   
-  virtual void WriteTrainFile(const std::string &strNewText);
+  virtual void WriteTrainFile(const std::string &filename, const std::string &strNewText);
   void Main(); 
 
   virtual std::string GetAllContext();
diff --git a/Src/iPhone/Classes/CDasherInterfaceBridge.h b/Src/iPhone/Classes/CDasherInterfaceBridge.h
index 515da97..e1ca468 100644
--- a/Src/iPhone/Classes/CDasherInterfaceBridge.h
+++ b/Src/iPhone/Classes/CDasherInterfaceBridge.h
@@ -43,6 +43,7 @@ public:
   void NewFrame(unsigned long iTime, bool bForceRedraw);
   
   void SetTiltAxes(Vec3 main, float off, Vec3 slow, float off2);
+  virtual void WriteTrainFile(const std::string &filename,const std::string &strNewText);
   bool SupportsClipboard() {return true;}
   void CopyToClipboard(const std::string &strText);
   bool SupportsSpeech();
@@ -56,7 +57,6 @@ private:
   virtual void SetupUI();
   virtual void CreateSettingsStore();
   virtual int GetFileSize(const std::string &strFileName);
-  virtual void WriteTrainFile(const std::string &strNewText);
   virtual void StartTimer();
   virtual void ShutdownTimer();
   
diff --git a/Src/iPhone/Classes/CDasherInterfaceBridge.mm b/Src/iPhone/Classes/CDasherInterfaceBridge.mm
index 554c25a..b7f2c2a 100644
--- a/Src/iPhone/Classes/CDasherInterfaceBridge.mm
+++ b/Src/iPhone/Classes/CDasherInterfaceBridge.mm
@@ -279,11 +279,11 @@ int CDasherInterfaceBridge::GetFileSize(const std::string &strFileName) {
 //  CDasherInterfaceBase::TrainFile(f, GetFileSize(f), 0);
 }*/
 
-void CDasherInterfaceBridge::WriteTrainFile(const std::string &strNewText) {
+void CDasherInterfaceBridge::WriteTrainFile(const std::string &filename,const std::string &strNewText) {
   if(strNewText.length() == 0)
     return;
   
-  std::string strFilename(GetStringParameter(SP_USER_LOC) + GetStringParameter(SP_TRAIN_FILE));
+  std::string strFilename(GetStringParameter(SP_USER_LOC) + filename);
   
   NSLog(@"Write train file: %s", strFilename.c_str());
   



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