From ab387a2ad8a09abcc863429f12110e954821a87a Mon Sep 17 00:00:00 2001 From: Sup Yut Sum Date: Mon, 1 Apr 2013 13:17:23 +0800 Subject: [PATCH] Multi-view edit I * Ask what file to save even more (both) are changed * Removing empty line do not mark view changed * For testing purposes new texts are constants Based on TortoiseSVN revision 24074 Signed-off-by: Sup Yut Sum --- src/TortoiseMerge/BaseView.cpp | 95 ++++++++++++++++++++++++++++++------- src/TortoiseMerge/BaseView.h | 5 ++ src/TortoiseMerge/FileTextLines.cpp | 39 +++++++-------- src/TortoiseMerge/FileTextLines.h | 14 ++++-- src/TortoiseMerge/MainFrm.cpp | 70 +++++++++++++++++++++++++++ 5 files changed, 183 insertions(+), 40 deletions(-) diff --git a/src/TortoiseMerge/BaseView.cpp b/src/TortoiseMerge/BaseView.cpp index e5417e170..608810ed9 100644 --- a/src/TortoiseMerge/BaseView.cpp +++ b/src/TortoiseMerge/BaseView.cpp @@ -1,4 +1,4 @@ -// TortoiseGitMerge - a Diff/Patch program +// TortoiseGitMerge - a Diff/Patch program // Copyright (C) 2003-2013 - TortoiseSVN // Copyright (C) 2011-2012 Sven Strickroth @@ -100,6 +100,7 @@ CBaseView::CBaseView() , m_bLimitToDiff(true) , m_bWholeWord(false) , m_pDC(NULL) + , m_pWorkingFile(NULL) { m_ptCaretViewPos.x = 0; m_ptCaretViewPos.y = 0; @@ -4463,21 +4464,6 @@ int CBaseView::CleanEmptyLines() } nViewLine++; } - if (nRemovedCount != 0) - { - if (bCheckLeft) - { - m_pwndLeft->SetModified(); - } - if (bCheckRight) - { - m_pwndRight->SetModified(); - } - if (bCheckBottom) - { - m_pwndBottom->SetModified(); - } - } return nRemovedCount; } @@ -5294,3 +5280,80 @@ void CBaseView::OnEditGotoline() } } +int CBaseView::SaveFile() +{ + Invalidate(); + if (m_pViewData!=NULL && m_pWorkingFile!=NULL) + { + CFileTextLines file; + //file.SetSaveParams(m_SaveParams); + + for (int i=0; iGetCount(); i++) + { + //only copy non-removed lines + DiffStates state = m_pViewData->GetState(i); + switch (state) + { + case DIFFSTATE_CONFLICTED: + case DIFFSTATE_CONFLICTED_IGNORED: + { + int first = i; + int last = i; + do + { + last++; + } while((lastGetCount()) && ((m_pViewData->GetState(last)==DIFFSTATE_CONFLICTED)||(m_pViewData->GetState(last)==DIFFSTATE_CONFLICTED_IGNORED))); + file.Add(_T("<<<<<<< .mine"), EOL_NOENDING); + for (int j=first; jm_pViewData->GetLine(j), m_pwndRight->m_pViewData->GetLineEnding(j)); + } + file.Add(_T("======="), EOL_NOENDING); + for (int j=first; jm_pViewData->GetLine(j), m_pwndLeft->m_pViewData->GetLineEnding(j)); + } + file.Add(_T(">>>>>>> .theirs"), EOL_NOENDING); + i = last-1; + } + break; + case DIFFSTATE_EMPTY: + case DIFFSTATE_CONFLICTEMPTY: + case DIFFSTATE_IDENTICALREMOVED: + case DIFFSTATE_REMOVED: + case DIFFSTATE_THEIRSREMOVED: + case DIFFSTATE_YOURSREMOVED: + case DIFFSTATE_CONFLICTRESOLVEDEMPTY: + // do not save removed lines + break; + default: + file.Add(m_pViewData->GetLine(i), m_pViewData->GetLineEnding(i)); + break; + } + } + if (!file.Save(m_pWorkingFile->GetFilename())) + { + ::MessageBox(m_hWnd, file.GetErrorString(), _T("TortoiseMerge"), MB_ICONERROR); + return -1; + } + m_pWorkingFile->StoreFileAttributes(); + // m_dlgFilePatches.SetFileStatusAsPatched(sFilePath); + SetModified(FALSE); + CUndo::GetInstance().MarkAsOriginalState(); + if (file.GetCount() == 1 && file.GetAt(0).IsEmpty() && file.GetLineEnding(0) == EOL_NOENDING) + return 0; + return file.GetCount(); + } + return 1; +} + + +int CBaseView::SaveFileTo(CString sFileName) +{ + if (m_pWorkingFile) + { + m_pWorkingFile->SetFileName(sFileName); + return SaveFile(); + } + return 1; +} diff --git a/src/TortoiseMerge/BaseView.h b/src/TortoiseMerge/BaseView.h index 4a784de32..f8d8fb8d0 100644 --- a/src/TortoiseMerge/BaseView.h +++ b/src/TortoiseMerge/BaseView.h @@ -226,6 +226,10 @@ public: // variables void GoToFirstDifference(); void GoToFirstConflict(); void AddEmptyViewLine(int nLineIndex); + int SaveFile(); + int SaveFileTo(CString FileName); + + CWorkingFile * m_pWorkingFile; ///< pointer to destination/source file parametrers protected: // methods enum { @@ -585,4 +589,5 @@ protected: // variables }; static Screen2View m_Screen2View; + CFileTextLines::SaveParams m_SaveParams; ///< encoding and new line style for saving }; diff --git a/src/TortoiseMerge/FileTextLines.cpp b/src/TortoiseMerge/FileTextLines.cpp index b57d30579..d9ebd66c2 100644 --- a/src/TortoiseMerge/FileTextLines.cpp +++ b/src/TortoiseMerge/FileTextLines.cpp @@ -51,10 +51,10 @@ UINT64 inline DwordSwapBytes(UINT64 nValue) } CFileTextLines::CFileTextLines(void) - : m_UnicodeType(CFileTextLines::AUTOTYPE) - , m_LineEndings(EOL_AUTOLINE) - , m_bNeedsConversion(false) + : m_bNeedsConversion(false) { + m_SaveParams.m_UnicodeType = CFileTextLines::AUTOTYPE; + m_SaveParams.m_LineEndings = EOL_AUTOLINE; } CFileTextLines::~CFileTextLines(void) @@ -168,8 +168,8 @@ CFileTextLines::UnicodeType CFileTextLines::CheckUnicodeType(LPVOID pBuffer, int BOOL CFileTextLines::Load(const CString& sFilePath, int lengthHint /* = 0*/) { WCHAR exceptionError[1000] = {0}; - m_LineEndings = EOL_AUTOLINE; - m_UnicodeType = CFileTextLines::AUTOTYPE; + m_SaveParams.m_LineEndings = EOL_AUTOLINE; + m_SaveParams.m_UnicodeType = CFileTextLines::AUTOTYPE; RemoveAll(); if(lengthHint != 0) { @@ -234,18 +234,18 @@ BOOL CFileTextLines::Load(const CString& sFilePath, int lengthHint /* = 0*/) hFile.CloseHandle(); // detect type - if (m_UnicodeType == CFileTextLines::AUTOTYPE) + if (m_SaveParams.m_UnicodeType == CFileTextLines::AUTOTYPE) { - m_UnicodeType = this->CheckUnicodeType((LPVOID)oFile, dwReadBytes); + m_SaveParams.m_UnicodeType = this->CheckUnicodeType((LPVOID)oFile, dwReadBytes); // enforce conversion for all but ASCII and UTF8 type - m_bNeedsConversion = (m_UnicodeType!=CFileTextLines::UTF8)&&(m_UnicodeType!=CFileTextLines::ASCII); + m_bNeedsConversion = (m_SaveParams.m_UnicodeType!=CFileTextLines::UTF8)&&(m_SaveParams.m_UnicodeType!=CFileTextLines::ASCII); } // we may have to convert the file content - CString is UTF16LE try { CBaseFilter * pFilter = NULL; - switch (m_UnicodeType) + switch (m_SaveParams.m_UnicodeType) { case BINARY: m_sErrorString.Format(IDS_ERR_FILE_BINARY, (LPCTSTR)sFilePath); @@ -284,11 +284,11 @@ BOOL CFileTextLines::Load(const CString& sFilePath, int lengthHint /* = 0*/) int nReadChars=oFile.GetLength()/sizeof(wchar_t); wchar_t * pTextBuf = (wchar_t *)oFile; wchar_t * pLineStart = pTextBuf; - if ((m_UnicodeType == UTF8BOM) - || (m_UnicodeType == UTF16_LE) - || (m_UnicodeType == UTF16_BE) - || (m_UnicodeType == UTF32_LE) - || (m_UnicodeType == UTF32_BE)) + if ((m_SaveParams.m_UnicodeType == UTF8BOM) + || (m_SaveParams.m_UnicodeType == UTF16_LE) + || (m_SaveParams.m_UnicodeType == UTF16_BE) + || (m_SaveParams.m_UnicodeType == UTF32_LE) + || (m_SaveParams.m_UnicodeType == UTF32_BE)) { // ignore the BOM ++pTextBuf; @@ -370,7 +370,7 @@ BOOL CFileTextLines::Load(const CString& sFilePath, int lengthHint /* = 0*/) if (eolmax < countEOLs[nEol]) { eolmax = countEOLs[nEol]; - m_LineEndings = (EOL)nEol; + m_SaveParams.m_LineEndings = (EOL)nEol; } } @@ -446,7 +446,7 @@ BOOL CFileTextLines::Save(const CString& sFilePath CBaseFilter * pFilter = NULL; bool bSaveBom = true; - CFileTextLines::UnicodeType eUnicodeType = bSaveAsUTF8 ? CFileTextLines::UTF8 : m_UnicodeType; + CFileTextLines::UnicodeType eUnicodeType = bSaveAsUTF8 ? CFileTextLines::UTF8 : m_SaveParams.m_UnicodeType; switch (eUnicodeType) { default: @@ -511,7 +511,9 @@ BOOL CFileTextLines::Save(const CString& sFilePath oEncodedEol[EOL_LS] = pFilter->Encode(_T("\x2028")); oEncodedEol[EOL_PS] = pFilter->Encode(_T("\x2029")); } - oEncodedEol[EOL_AUTOLINE] = oEncodedEol[m_LineEndings==EOL_AUTOLINE ? EOL_CRLF : m_LineEndings]; + oEncodedEol[EOL_AUTOLINE] = oEncodedEol[m_SaveParams.m_LineEndings==EOL_AUTOLINE + ? EOL_CRLF + : m_SaveParams.m_LineEndings]; for (int i=0; im_UnicodeType = m_UnicodeType; - pFileToCopySettingsTo->m_LineEndings = m_LineEndings; + pFileToCopySettingsTo->m_SaveParams = m_SaveParams; } } diff --git a/src/TortoiseMerge/FileTextLines.h b/src/TortoiseMerge/FileTextLines.h index 69988a9ae..32f31a1e0 100644 --- a/src/TortoiseMerge/FileTextLines.h +++ b/src/TortoiseMerge/FileTextLines.h @@ -97,6 +97,11 @@ public: UTF8BOM, //=UTF8+65536, }; + struct SaveParams { + UnicodeType m_UnicodeType; + EOL m_LineEndings; + }; + /** * Loads the text file and adds each line to the array * \param sFilePath the path to the file @@ -130,8 +135,8 @@ public: void CopySettings(CFileTextLines * pFileToCopySettingsTo); bool NeedsConversion() const { return m_bNeedsConversion; } - CFileTextLines::UnicodeType GetUnicodeType() const {return m_UnicodeType;} - EOL GetLineEndings() const {return m_LineEndings;} + UnicodeType GetUnicodeType() const {return m_SaveParams.m_UnicodeType;} + EOL GetLineEndings() const {return m_SaveParams.m_LineEndings;} using CStdFileLineArray::Add; void Add(const CString& sLine, EOL ending) { CFileTextLine temp={sLine, ending}; CStdFileLineArray::Add(temp); } @@ -151,7 +156,7 @@ public: * \param pBuffer pointer to the buffer containing text * \param cb size of the text buffer in bytes */ - CFileTextLines::UnicodeType CheckUnicodeType(LPVOID pBuffer, int cb); + UnicodeType CheckUnicodeType(LPVOID pBuffer, int cb); private: void SetErrorString(); @@ -161,9 +166,8 @@ private: private: CString m_sErrorString; - UnicodeType m_UnicodeType; - EOL m_LineEndings; bool m_bNeedsConversion; + SaveParams m_SaveParams; }; diff --git a/src/TortoiseMerge/MainFrm.cpp b/src/TortoiseMerge/MainFrm.cpp index 61193251b..e34c7f0d1 100644 --- a/src/TortoiseMerge/MainFrm.cpp +++ b/src/TortoiseMerge/MainFrm.cpp @@ -758,9 +758,12 @@ bool CMainFrame::LoadViews(int line) m_pwndLeftView->lineendings = m_Data.m_arYourFile.GetLineEndings(); m_pwndLeftView->m_sWindowName = m_Data.m_baseFile.GetWindowName() + _T(" - ") + m_Data.m_yourFile.GetWindowName(); m_pwndLeftView->m_sFullFilePath = m_Data.m_baseFile.GetFilename() + _T(" - ") + m_Data.m_yourFile.GetFilename(); + m_pwndLeftView->m_pWorkingFile = &m_Data.m_yourFile; m_pwndRightView->m_pViewData = NULL; + m_pwndRightView->m_pWorkingFile = NULL; m_pwndBottomView->m_pViewData = NULL; + m_pwndBottomView->m_pWorkingFile = NULL; if (!m_wndSplitter.IsRowHidden(1)) m_wndSplitter.HideRow(1); @@ -781,6 +784,7 @@ bool CMainFrame::LoadViews(int line) m_pwndLeftView->m_sWindowName = m_Data.m_baseFile.GetWindowName(); m_pwndLeftView->m_sFullFilePath = m_Data.m_baseFile.GetFilename(); m_pwndLeftView->m_sConvertedFilePath = m_Data.m_baseFile.GetConvertedFileName(); + m_pwndLeftView->m_pWorkingFile = &m_Data.m_baseFile; m_pwndRightView->m_pViewData = &m_Data.m_YourBaseRight; m_pwndRightView->texttype = m_Data.m_arYourFile.GetUnicodeType(); @@ -788,8 +792,10 @@ bool CMainFrame::LoadViews(int line) m_pwndRightView->m_sWindowName = m_Data.m_yourFile.GetWindowName(); m_pwndRightView->m_sFullFilePath = m_Data.m_yourFile.GetFilename(); m_pwndRightView->m_sConvertedFilePath = m_Data.m_yourFile.GetConvertedFileName(); + m_pwndRightView->m_pWorkingFile = &m_Data.m_yourFile; m_pwndBottomView->m_pViewData = NULL; + m_pwndBottomView->m_pWorkingFile = NULL; if (!m_wndSplitter.IsRowHidden(1)) m_wndSplitter.HideRow(1); @@ -812,6 +818,7 @@ bool CMainFrame::LoadViews(int line) m_pwndLeftView->m_sWindowName += _T(" - ") + m_Data.m_theirFile.GetWindowName(); m_pwndLeftView->m_sFullFilePath = m_Data.m_theirFile.GetFilename(); m_pwndLeftView->m_sConvertedFilePath = m_Data.m_theirFile.GetConvertedFileName(); + m_pwndLeftView->m_pWorkingFile = &m_Data.m_theirFile; m_pwndRightView->m_pViewData = &m_Data.m_YourBaseBoth; m_pwndRightView->texttype = m_Data.m_arYourFile.GetUnicodeType(); @@ -820,6 +827,7 @@ bool CMainFrame::LoadViews(int line) m_pwndRightView->m_sWindowName += _T(" - ") + m_Data.m_yourFile.GetWindowName(); m_pwndRightView->m_sFullFilePath = m_Data.m_yourFile.GetFilename(); m_pwndRightView->m_sConvertedFilePath = m_Data.m_yourFile.GetConvertedFileName(); + m_pwndRightView->m_pWorkingFile = &m_Data.m_yourFile; m_pwndBottomView->m_pViewData = &m_Data.m_Diff3; m_pwndBottomView->texttype = m_Data.m_arTheirFile.GetUnicodeType(); @@ -828,6 +836,7 @@ bool CMainFrame::LoadViews(int line) m_pwndBottomView->m_sWindowName += _T(" - ") + m_Data.m_mergedFile.GetWindowName(); m_pwndBottomView->m_sFullFilePath = m_Data.m_mergedFile.GetFilename(); m_pwndBottomView->m_sConvertedFilePath = m_Data.m_mergedFile.GetConvertedFileName(); + m_pwndBottomView->m_pWorkingFile = &m_Data.m_mergedFile; if (m_wndSplitter2.IsColumnHidden(1)) m_wndSplitter2.ShowColumn(); @@ -2026,6 +2035,67 @@ int CMainFrame::CheckForSave(ECheckForSaveReason eReason) break; } + // TODO simplify logic, reduce code duplication + if (CBaseView::IsViewGood(m_pwndBottomView)) + { + // three-way diff - by design only bottom can be changed + } + else if (CBaseView::IsViewGood(m_pwndRightView)) + { + // two-way diff - + // in 1.7 version only right was saved, now left and/or right can be save, so we need to indicate what we are asking to save + if (HasUnsavedEdits(m_pwndLeftView)) + { + // both views + UINT ret = IDNO; + { + // show separate questions + // first show question for left view + ret = MessageBox(sTitle, 0, MB_YESNOCANCEL | MB_ICONQUESTION); + if (ret == IDCANCEL) + { + return IDCANCEL; + } + if (ret == IDYES) + { + if (m_pwndLeftView->SaveFile()<0) + { + return IDCANCEL; + } + } + // right file is handled old way + } + } + else + { + // only secondary (left) view + } + // otherwise 1.7 behaviour is used + } + else if (CBaseView::IsViewGood(m_pwndLeftView)) + { + // only one view - only one to save + // 1.7 FileSave don't support this mode + if (HasUnsavedEdits(m_pwndLeftView)) + { + UINT ret = IDNO; + { + ret = MessageBox(sTitle, 0, MB_YESNOCANCEL | MB_ICONQUESTION); + } + + if (ret == IDYES) + { + if (m_pwndLeftView->SaveFile()<0) + return IDCANCEL; + } + } + return IDNO; + } + else + { + return IDNO; // nothing to save + } + UINT ret = IDNO; if (HasUnsavedEdits()) { -- 2.11.4.GIT