OSDN Git Service

Binary Compare: Fix the problem that the file cannot be saved after creating a new one
[winmerge-jp/winmerge-jp.git] / Src / HexMergeDoc.cpp
index ce63e49..824a81e 100644 (file)
@@ -2,21 +2,7 @@
 //    WinMerge:  an interactive diff/merge utility
 //    Copyright (C) 1997-2000  Thingamahoochie Software
 //    Author: Dean Grimm
-//
-//    This program is free software; you can redistribute it and/or modify
-//    it under the terms of the GNU General Public License as published by
-//    the Free Software Foundation; either version 2 of the License, or
-//    (at your option) any later version.
-//
-//    This program is distributed in the hope that it will be useful,
-//    but WITHOUT ANY WARRANTY; without even the implied warranty of
-//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//    GNU General Public License for more details.
-//
-//    You should have received a copy of the GNU General Public License
-//    along with this program; if not, write to the Free Software
-//    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-//
+//    SPDX-License-Identifier: GPL-2.0-or-later
 /////////////////////////////////////////////////////////////////////////////
 /** 
  * @file  HexMergeDoc.cpp
  * @brief Implementation file for CHexMergeDoc
  *
  */
-// ID line follows -- this is updated by SVN
-// $Id: HexMergeDoc.cpp 7166 2010-05-16 12:05:13Z jtuc $
 
 #include "stdafx.h"
 #include "HexMergeDoc.h"
 #include <afxinet.h>
 #include "UnicodeString.h"
-#include "FileTextEncoding.h"
-#include "Merge.h"
 #include "HexMergeFrm.h"
 #include "HexMergeView.h"
 #include "DiffItem.h"
 #include "FolderCmp.h"
-#include "Environment.h"
 #include "DiffContext.h"       // FILE_SAME
 #include "DirDoc.h"
 #include "DirActions.h"
 #include "OptionsMgr.h"
 #include "FileOrFolderSelect.h"
 #include "DiffWrapper.h"
+#include "SyntaxColors.h"
+#include "Merge.h"
+#include "Constants.h"
+#include "MainFrm.h"
 
 #ifdef _DEBUG
 #define new DEBUG_NEW
-#undef THIS_FILE
-static char THIS_FILE[] = __FILE__;
 #endif
 
 int CHexMergeDoc::m_nBuffersTemp = 2;
@@ -66,46 +49,18 @@ static int Try(HRESULT hr, UINT type = MB_OKCANCEL|MB_ICONSTOP);
  */
 static void UpdateDiffItem(int nBuffers, DIFFITEM &di, CDiffContext *pCtxt)
 {
-       di.diffcode.diffcode |= DIFFCODE::SIDEFLAGS;
+       di.diffcode.setSideNone();
        for (int nBuffer = 0; nBuffer < nBuffers; nBuffer++)
        {
                di.diffFileInfo[nBuffer].ClearPartial();
-               di.diffFileInfo[nBuffer].ClearPartial();
-               if (!pCtxt->UpdateInfoFromDiskHalf(di, nBuffer))
-               {
-                       if (nBuffer == 0)
-                               di.diffcode.diffcode &= ~DIFFCODE::FIRST;
-                       else if (nBuffer == 1)
-                               di.diffcode.diffcode &= ~DIFFCODE::SECOND;
-                       else
-                               di.diffcode.diffcode &= ~DIFFCODE::THIRD;
-               }
-       }
-       // 1. Clear flags
-       di.diffcode.diffcode &= ~(DIFFCODE::TEXTFLAGS | DIFFCODE::COMPAREFLAGS);
-       // 2. Process unique files
-       // We must compare unique files to itself to detect encoding
-       if (!di.diffcode.existAll(nBuffers))
-       {
-               int compareMethod = pCtxt->GetCompareMethod();
-               if (compareMethod != CMP_DATE && compareMethod != CMP_DATE_SIZE &&
-                       compareMethod != CMP_SIZE)
-               {
-                       di.diffcode.diffcode |= DIFFCODE::SAME;
-                       FolderCmp folderCmp;
-                       int diffCode = folderCmp.prepAndCompareFiles(pCtxt, di);
-                       // Add possible binary flag for unique items
-                       if (diffCode & DIFFCODE::BIN)
-                               di.diffcode.diffcode |= DIFFCODE::BIN;
-               }
-       }
-       // 3. Compare two files
-       else
-       {
-               // Really compare
-               FolderCmp folderCmp;
-               di.diffcode.diffcode |= folderCmp.prepAndCompareFiles(pCtxt, di);
+               if (pCtxt->UpdateInfoFromDiskHalf(di, nBuffer))
+                       di.diffcode.diffcode |= DIFFCODE::FIRST << nBuffer;
        }
+       // Clear flags
+       di.diffcode.diffcode &= ~(DIFFCODE::TEXTFLAGS | DIFFCODE::COMPAREFLAGS | DIFFCODE::COMPAREFLAGS3WAY);
+       // Really compare
+       FolderCmp folderCmp(pCtxt);
+       di.diffcode.diffcode |= folderCmp.prepAndCompareFiles(di);
 }
 
 /**
@@ -142,6 +97,9 @@ BEGIN_MESSAGE_MAP(CHexMergeDoc, CDocument)
        ON_COMMAND(ID_VIEW_ZOOMIN, OnViewZoomIn)
        ON_COMMAND(ID_VIEW_ZOOMOUT, OnViewZoomOut)
        ON_COMMAND(ID_VIEW_ZOOMNORMAL, OnViewZoomNormal)
+       ON_COMMAND(ID_REFRESH, OnRefresh)
+       ON_COMMAND_RANGE(ID_MERGE_COMPARE_TEXT, ID_MERGE_COMPARE_IMAGE, OnFileRecompareAs)
+       ON_UPDATE_COMMAND_UI_RANGE(ID_MERGE_COMPARE_TEXT, ID_MERGE_COMPARE_IMAGE, OnUpdateFileRecompareAs)
        //}}AFX_MSG_MAP
 END_MESSAGE_MAP()
 
@@ -152,11 +110,12 @@ END_MESSAGE_MAP()
  * @brief Constructor.
  */
 CHexMergeDoc::CHexMergeDoc()
-: m_pDirDoc(NULL)
+: m_pDirDoc(nullptr)
+, m_nBuffers(m_nBuffersTemp)
+, m_pView{}
+, m_nBufferType{BUFFERTYPE::NORMAL, BUFFERTYPE::NORMAL, BUFFERTYPE::NORMAL}
 {
-       m_nBuffers = m_nBuffersTemp;
-       std::fill_n(m_pView, m_nBuffers, static_cast<CHexMergeView *>(NULL));
-       std::fill_n(m_nBufferType, m_nBuffers, BUFFER_NORMAL);
+       m_filePaths.SetSize(m_nBuffers);
 }
 
 /**
@@ -166,7 +125,7 @@ CHexMergeDoc::CHexMergeDoc()
  */
 CHexMergeDoc::~CHexMergeDoc()
 {      
-       if (m_pDirDoc)
+       if (m_pDirDoc != nullptr)
                m_pDirDoc->MergeDocClosing(this);
 }
 
@@ -177,7 +136,7 @@ CHexMergeView * CHexMergeDoc::GetActiveMergeView() const
 {
        CView * pActiveView = GetParentFrame()->GetActiveView();
        CHexMergeView * pHexMergeView = dynamic_cast<CHexMergeView *>(pActiveView);
-       if (!pHexMergeView)
+       if (pHexMergeView == nullptr)
                pHexMergeView = m_pView[0]; // default to left view (in case some location or detail view active)
        return pHexMergeView;
 }
@@ -185,28 +144,26 @@ CHexMergeView * CHexMergeDoc::GetActiveMergeView() const
 /**
  * @brief Update associated diff item
  */
-void CHexMergeDoc::UpdateDiffItem(CDirDoc *pDirDoc)
+int CHexMergeDoc::UpdateDiffItem(CDirDoc *pDirDoc)
 {
        // If directory compare has results
-       if (pDirDoc && pDirDoc->HasDiffs())
+       if (pDirDoc != nullptr && pDirDoc->HasDiffs())
        {
-               const String &pathLeft = m_filePaths.GetLeft();
-               const String &pathRight = m_filePaths.GetRight();
                CDiffContext &ctxt = pDirDoc->GetDiffContext();
-               if (UINT_PTR pos = FindItemFromPaths(ctxt, pathLeft, pathRight))
+               if (DIFFITEM *pos = FindItemFromPaths(ctxt, m_filePaths))
                {
                        DIFFITEM &di = ctxt.GetDiffRefAt(pos);
                        ::UpdateDiffItem(m_nBuffers, di, &ctxt);
                }
        }
-       BOOL bDiff = FALSE;
+       bool bDiff = false;
        int lengthFirst = m_pView[0]->GetLength();
        void *bufferFirst = m_pView[0]->GetBuffer(lengthFirst);
        for (int nBuffer = 1; nBuffer < m_nBuffers; nBuffer++)
        {
                int length = m_pView[nBuffer]->GetLength();
                if (lengthFirst != length)
-                       bDiff = TRUE;
+                       bDiff = true;
                else
                {
                        void *buffer = m_pView[nBuffer]->GetBuffer(length);
@@ -216,34 +173,35 @@ void CHexMergeDoc::UpdateDiffItem(CDirDoc *pDirDoc)
                        break;
        }
        GetParentFrame()->SetLastCompareResult(bDiff);
+       return bDiff ? 1 : 0;
 }
 
 /**
  * @brief Asks and then saves modified files
  */
-BOOL CHexMergeDoc::PromptAndSaveIfNeeded(BOOL bAllowCancel)
+bool CHexMergeDoc::PromptAndSaveIfNeeded(bool bAllowCancel)
 {
        bool bLModified = false, bMModified = false, bRModified = false;
 
        if (m_nBuffers == 3)
        {
-               bLModified = !!m_pView[0]->GetModified();
-               bMModified = !!m_pView[1]->GetModified();
-               bRModified = !!m_pView[2]->GetModified();
+               bLModified = m_pView[0]->GetModified();
+               bMModified = m_pView[1]->GetModified();
+               bRModified = m_pView[2]->GetModified();
        }
        else
        {
-               bLModified = !!m_pView[0]->GetModified();
-               bRModified = !!m_pView[1]->GetModified();
+               bLModified = m_pView[0]->GetModified();
+               bRModified = m_pView[1]->GetModified();
        }
        if (!bLModified && !bMModified && !bRModified)
-                return TRUE;
+                return true;
 
        const String &pathLeft = m_filePaths.GetLeft();
        const String &pathMiddle = m_filePaths.GetMiddle();
        const String &pathRight = m_filePaths.GetRight();
 
-       BOOL result = TRUE;
+       bool result = true;
        bool bLSaveSuccess = false, bMSaveSuccess = false, bRSaveSuccess = false;
 
        SaveClosingDlg dlg;
@@ -272,63 +230,45 @@ BOOL CHexMergeDoc::PromptAndSaveIfNeeded(BOOL bAllowCancel)
                {
                        if (dlg.m_leftSave == SaveClosingDlg::SAVECLOSING_SAVE)
                        {
-                               switch (Try(m_pView[0]->SaveFile(pathLeft.c_str())))
-                               {
-                               case 0:
-                                       bLSaveSuccess = TRUE;
-                                       break;
-                               case IDCANCEL:
-                                       result = FALSE;
-                                       break;
-                               }
+                               bLSaveSuccess = DoFileSave(0);
+                               if (!bLSaveSuccess)
+                                       result = false;
                        }
                        else
                        {
-                               m_pView[0]->SetModified(FALSE);
+                               m_pView[0]->SetSavePoint();
                        }
                }
                if (bMModified)
                {
                        if (dlg.m_middleSave == SaveClosingDlg::SAVECLOSING_SAVE)
                        {
-                               switch (Try(m_pView[1]->SaveFile(pathMiddle.c_str())))
-                               {
-                               case 0:
-                                       bMSaveSuccess = TRUE;
-                                       break;
-                               case IDCANCEL:
-                                       result = FALSE;
-                                       break;
-                               }
+                               bMSaveSuccess = DoFileSave(1);
+                               if (!bMSaveSuccess)
+                                       result = false;
                        }
                        else
                        {
-                               m_pView[1]->SetModified(FALSE);
+                               m_pView[1]->SetSavePoint();
                        }
                }
                if (bRModified)
                {
                        if (dlg.m_rightSave == SaveClosingDlg::SAVECLOSING_SAVE)
                        {
-                               switch (Try(m_pView[m_nBuffers - 1]->SaveFile(pathRight.c_str())))
-                               {
-                               case 0:
-                                       bRSaveSuccess = TRUE;
-                                       break;
-                               case IDCANCEL:
-                                       result = FALSE;
-                                       break;
-                               }
+                               bRSaveSuccess = DoFileSave(m_nBuffers - 1);
+                               if (!bRSaveSuccess)
+                                       result = false;
                        }
                        else
                        {
-                               m_pView[m_nBuffers - 1]->SetModified(FALSE);
+                               m_pView[m_nBuffers - 1]->SetSavePoint();
                        }
                }
        }
        else
        {       
-               result = FALSE;
+               result = false;
        }
 
        // If file were modified and saving was successfull,
@@ -346,7 +286,7 @@ BOOL CHexMergeDoc::PromptAndSaveIfNeeded(BOOL bAllowCancel)
  */
 BOOL CHexMergeDoc::SaveModified()
 {
-       return PromptAndSaveIfNeeded(TRUE);
+       return PromptAndSaveIfNeeded(true);
 }
 
 /**
@@ -358,23 +298,30 @@ void CHexMergeDoc::OnFileSave()
                DoFileSave(nBuffer);
 }
 
-void CHexMergeDoc::DoFileSave(int nBuffer)
+bool CHexMergeDoc::DoFileSave(int nBuffer)
 {
+       bool result = false;
        if (m_pView[nBuffer]->GetModified())
        {
-               if (m_nBufferType[nBuffer] == BUFFER_UNNAMED)
-                       DoFileSaveAs(nBuffer);
+               if (m_nBufferType[nBuffer] == BUFFERTYPE::UNNAMED)
+                       result = DoFileSaveAs(nBuffer);
                else
                {
                        const String &path = m_filePaths.GetPath(nBuffer);
-                       if (Try(m_pView[nBuffer]->SaveFile(path.c_str())) == IDCANCEL)
-                               return;
+                       HRESULT hr = m_pView[nBuffer]->SaveFile(path.c_str());
+                       if (Try(hr) == IDCANCEL)
+                               return false;
+                       if (FAILED(hr))
+                               return DoFileSaveAs(nBuffer);
+                       result = true;
+                       if (result)
+                               UpdateDiffItem(m_pDirDoc);
                }
-               UpdateDiffItem(m_pDirDoc);
        }
+       return result;
 }
 
-void CHexMergeDoc::DoFileSaveAs(int nBuffer)
+bool CHexMergeDoc::DoFileSaveAs(int nBuffer, bool packing)
 {
        const String &path = m_filePaths.GetPath(nBuffer);
        String strPath;
@@ -385,21 +332,26 @@ void CHexMergeDoc::DoFileSaveAs(int nBuffer)
                title = _("Save Right File As");
        else
                title = _("Save Middle File As");
-       if (SelectFile(AfxGetMainWnd()->GetSafeHwnd(), strPath, path.c_str(), title, _T(""), FALSE))
+       if (SelectFile(AfxGetMainWnd()->GetSafeHwnd(), strPath, false, path.c_str(), title))
        {
-               if (Try(m_pView[nBuffer]->SaveFile(strPath.c_str())) == IDCANCEL)
-                       return;
+               HRESULT hr = m_pView[nBuffer]->SaveFile(strPath.c_str());
+               if (Try(hr) == IDCANCEL)
+                       return false;
+               if (FAILED(hr))
+                       return false;
                if (path.empty())
                {
                        // We are saving scratchpad (unnamed file)
-                       m_nBufferType[nBuffer] = BUFFER_UNNAMED_SAVED;
+                       m_nBufferType[nBuffer] = BUFFERTYPE::UNNAMED_SAVED;
                        m_strDesc[nBuffer].erase();
                }
 
                m_filePaths.SetPath(nBuffer, strPath);
                UpdateDiffItem(m_pDirDoc);
                UpdateHeaderPath(nBuffer);
+               return true;
        }
+       return false;
 }
 
 /**
@@ -464,7 +416,7 @@ void CHexMergeDoc::OnUpdateStatusNum(CCmdUI* pCmdUI)
  */
 void CHexMergeDoc::SetDirDoc(CDirDoc * pDirDoc)
 {
-       ASSERT(pDirDoc && !m_pDirDoc);
+       ASSERT(pDirDoc != nullptr && m_pDirDoc == nullptr);
        m_pDirDoc = pDirDoc;
 }
 
@@ -482,7 +434,7 @@ CHexMergeFrame * CHexMergeDoc::GetParentFrame() const
 void CHexMergeDoc::DirDocClosing(CDirDoc * pDirDoc)
 {
        ASSERT(m_pDirDoc == pDirDoc);
-       m_pDirDoc = 0;
+       m_pDirDoc = nullptr;
 }
 
 /**
@@ -491,7 +443,7 @@ void CHexMergeDoc::DirDocClosing(CDirDoc * pDirDoc)
 bool CHexMergeDoc::CloseNow()
 {
        // Allow user to cancel closing
-       if (!PromptAndSaveIfNeeded(TRUE))
+       if (!PromptAndSaveIfNeeded(true))
                return false;
 
        GetParentFrame()->CloseNow();
@@ -501,7 +453,7 @@ bool CHexMergeDoc::CloseNow()
 /**
 * @brief Load one file
 */
-HRESULT CHexMergeDoc::LoadOneFile(int index, LPCTSTR filename, BOOL readOnly)
+HRESULT CHexMergeDoc::LoadOneFile(int index, LPCTSTR filename, bool readOnly, const String& strDesc)
 {
        if (filename[0])
        {
@@ -509,19 +461,17 @@ HRESULT CHexMergeDoc::LoadOneFile(int index, LPCTSTR filename, BOOL readOnly)
                        return E_FAIL;
                m_pView[index]->SetReadOnly(readOnly);
                m_filePaths.SetPath(index, filename);
-               ASSERT(m_nBufferType[index] == BUFFER_NORMAL); // should have been initialized to BUFFER_NORMAL in constructor
-               String strDesc = theApp.m_strDescriptions[index];
+               ASSERT(m_nBufferType[index] == BUFFERTYPE::NORMAL); // should have been initialized to BUFFERTYPE::NORMAL in constructor
                if (!strDesc.empty())
                {
                        m_strDesc[index] = strDesc;
-                       m_nBufferType[index] = BUFFER_NORMAL_NAMED;
+                       m_nBufferType[index] = BUFFERTYPE::NORMAL_NAMED;
                }
        }
        else
        {
-               m_nBufferType[index] = BUFFER_UNNAMED;
-               m_strDesc[index] = theApp.m_strDescriptions[index];
-
+               m_nBufferType[index] = BUFFERTYPE::UNNAMED;
+               m_strDesc[index] = strDesc;
        }
        UpdateHeaderPath(index);
        m_pView[index]->ResizeWindow();
@@ -531,41 +481,64 @@ HRESULT CHexMergeDoc::LoadOneFile(int index, LPCTSTR filename, BOOL readOnly)
 /**
  * @brief Load files and initialize frame's compare result icon
  */
-HRESULT CHexMergeDoc::OpenDocs(const PathContext &paths, const bool bRO[])
+bool CHexMergeDoc::OpenDocs(int nFiles, const FileLocation fileloc[], const bool bRO[], const String strDesc[])
 {
        CHexMergeFrame *pf = GetParentFrame();
-       ASSERT(pf);
-       HRESULT hr;
+       ASSERT(pf != nullptr);
+       bool bSucceeded = true;
+       int nNormalBuffer = 0;
        int nBuffer;
-       for (nBuffer = 0; nBuffer < m_nBuffers; nBuffer++)
+       for (nBuffer = 0; nBuffer < nFiles; nBuffer++)
        {
-               if (FAILED(hr = LoadOneFile(nBuffer, paths.GetPath(nBuffer).c_str(), bRO[nBuffer])))
+               if (FAILED(LoadOneFile(nBuffer, fileloc[nBuffer].filepath.c_str(), bRO[nBuffer], strDesc ? strDesc[nBuffer] : _T(""))))
+               {
+                       bSucceeded = false;
                        break;
+               }
+               if (m_nBufferType[nBuffer] == BUFFERTYPE::NORMAL || m_nBufferType[nBuffer] == BUFFERTYPE::NORMAL_NAMED)
+                       ++nNormalBuffer;
        }
-       if (nBuffer == m_nBuffers)
+       if (nBuffer == nFiles)
        {
-               UpdateDiffItem(0);
                // An extra ResizeWindow() on the left view aligns scroll ranges, and
                // also triggers initial diff coloring by invalidating the client area.
                m_pView[0]->ResizeWindow();
-               if (GetOptionsMgr()->GetBool(OPT_SCROLL_TO_FIRST))
-                       m_pView[0]->SendMessage(WM_COMMAND, ID_FIRSTDIFF);
+
+               if (nNormalBuffer > 0)
+                       OnRefresh();
+               else
+                       UpdateDiffItem(m_pDirDoc);
        }
        else
        {
                // Use verify macro to trap possible error in debug.
                VERIFY(pf->DestroyWindow());
        }
-       return hr;
+       return bSucceeded;
+}
+
+void CHexMergeDoc::MoveOnLoad(int nPane, int)
+{
+       if (nPane < 0)
+       {
+               nPane = GetOptionsMgr()->GetInt(OPT_ACTIVE_PANE);
+               if (nPane < 0 || nPane >= m_nBuffers)
+                       nPane = 0;
+       }
+
+       GetParentFrame()->SetActivePane(nPane);
+
+       if (GetOptionsMgr()->GetBool(OPT_SCROLL_TO_FIRST))
+               m_pView[0]->SendMessage(WM_COMMAND, ID_FIRSTDIFF);
 }
 
 void CHexMergeDoc::CheckFileChanged(void)
 {
        for (int pane = 0; pane < m_nBuffers; ++pane)
        {
-               if (m_pView[pane]->IsFileChangedOnDisk(m_filePaths[pane].c_str()))
+               if (m_pView[pane]->IsFileChangedOnDisk(m_filePaths[pane].c_str()) == FileChange::Changed)
                {
-                       String msg = string_format_string1(_("Another application has updated file\n%1\nsince WinMerge scanned it last time.\n\nDo you want to reload the file?"), m_filePaths[pane]);
+                       String msg = strutils::format_string1(_("Another application has updated file\n%1\nsince WinMerge scanned it last time.\n\nDo you want to reload the file?"), m_filePaths[pane]);
                        if (AfxMessageBox(msg.c_str(), MB_YESNO | MB_ICONWARNING) == IDYES)
                        {
                                OnFileReload();
@@ -582,46 +555,89 @@ void CHexMergeDoc::CheckFileChanged(void)
 void CHexMergeDoc::UpdateHeaderPath(int pane)
 {
        CHexMergeFrame *pf = GetParentFrame();
-       ASSERT(pf);
+       ASSERT(pf != nullptr);
        String sText;
 
-       if (m_nBufferType[pane] == BUFFER_UNNAMED ||
-               m_nBufferType[pane] == BUFFER_NORMAL_NAMED)
+       if (m_nBufferType[pane] == BUFFERTYPE::UNNAMED ||
+               m_nBufferType[pane] == BUFFERTYPE::NORMAL_NAMED)
        {
                sText = m_strDesc[pane];
        }
        else
        {
                sText = m_filePaths.GetPath(pane);
-               if (m_pDirDoc)
+               if (m_pDirDoc != nullptr)
                        m_pDirDoc->ApplyDisplayRoot(pane, sText);
        }
        if (m_pView[pane]->GetModified())
                sText.insert(0, _T("* "));
        pf->GetHeaderInterface()->SetText(pane, sText);
 
-       SetTitle(NULL);
+       SetTitle(nullptr);
 }
 
+
 /**
- * @brief Update document filenames to title
+ * @brief Customize a heksedit control's settings
  */
-void CHexMergeDoc::SetTitle(LPCTSTR lpszTitle)
+static void Customize(IHexEditorWindow::Settings *settings)
 {
-       String sTitle;
-       String sFileName[3];
+       settings->bSaveIni = false;
+       //settings->iAutomaticBPL = false;
+       //settings->iBytesPerLine = 16;
+       //settings->iFontSize = 8;
+}
 
-       if (lpszTitle)
-               sTitle = lpszTitle;
-       else
+/**
+ * @brief Customize a heksedit control's colors
+ */
+static void Customize(IHexEditorWindow::Colors *colors)
+{
+       COptionsMgr *pOptionsMgr = GetOptionsMgr();
+       colors->iSelBkColorValue = RGB(224, 224, 224);
+       colors->iDiffBkColorValue = pOptionsMgr->GetInt(OPT_CLR_DIFF);
+       colors->iSelDiffBkColorValue = pOptionsMgr->GetInt(OPT_CLR_SELECTED_DIFF);
+       colors->iDiffTextColorValue = pOptionsMgr->GetInt(OPT_CLR_DIFF_TEXT);
+       if (colors->iDiffTextColorValue == 0xFFFFFFFF)
+               colors->iDiffTextColorValue = 0;
+       colors->iSelDiffTextColorValue = pOptionsMgr->GetInt(OPT_CLR_SELECTED_DIFF_TEXT);
+       if (colors->iSelDiffTextColorValue == 0xFFFFFFFF)
+               colors->iSelDiffTextColorValue = 0;
+       SyntaxColors *pSyntaxColors = theApp.GetMainSyntaxColors();
+       colors->iTextColorValue = pSyntaxColors->GetColor(COLORINDEX_NORMALTEXT);
+       colors->iBkColorValue = pSyntaxColors->GetColor(COLORINDEX_BKGND);
+       colors->iSelTextColorValue = pSyntaxColors->GetColor(COLORINDEX_SELTEXT);
+       colors->iSelBkColorValue = pSyntaxColors->GetColor(COLORINDEX_SELBKGND);
+}
+
+/**
+ * @brief Customize a heksedit control's settings and colors
+ */
+static void Customize(IHexEditorWindow *pif)
+{
+       Customize(pif->get_settings());
+       Customize(pif->get_colors());
+       //LANGID wLangID = (LANGID)GetThreadLocale();
+       //pif->load_lang(wLangID);
+}
+
+void CHexMergeDoc::RefreshOptions()
+{
+       for (int nBuffer = 0; nBuffer < m_nBuffers; nBuffer++)
        {
-               for (int nBuffer = 0; nBuffer < m_filePaths.GetSize(); nBuffer++)
-                       sFileName[nBuffer] = !m_strDesc[nBuffer].empty() ? m_strDesc[nBuffer] : paths_FindFileName(m_filePaths[nBuffer]);
-               if (std::count(&sFileName[0], &sFileName[0] + m_nBuffers, sFileName[0]) == m_nBuffers)
-                       sTitle = sFileName[0] + string_format(_T(" x %d"), m_nBuffers);
-               else
-                       sTitle = string_join(&sFileName[0], &sFileName[0] + m_nBuffers, _T(" - "));
+               IHexEditorWindow *pif = m_pView[nBuffer]->GetInterface();
+               pif->read_ini_data();
+               Customize(pif);
+               pif->resize_window();
        }
+}
+
+/**
+ * @brief Update document filenames to title
+ */
+void CHexMergeDoc::SetTitle(LPCTSTR lpszTitle)
+{
+       String sTitle = (lpszTitle != nullptr) ? lpszTitle : CMergeFrameCommon::GetTitleString(m_filePaths, m_strDesc);
        CDocument::SetTitle(sTitle.c_str());
 }
 
@@ -633,7 +649,7 @@ void CHexMergeDoc::SetMergeViews(CHexMergeView *pView[])
 {
        for (int nBuffer = 0; nBuffer < m_nBuffers; nBuffer++)
        {
-               ASSERT(pView[nBuffer] && !m_pView[nBuffer]);
+               ASSERT(pView[nBuffer] != nullptr && m_pView[nBuffer] == nullptr);
                m_pView[nBuffer] = pView[nBuffer];
                m_pView[nBuffer]->m_nThisPane = nBuffer;
        }
@@ -668,7 +684,7 @@ void CHexMergeDoc::OnUpdateFileSaveRight(CCmdUI* pCmdUI)
  */
 void CHexMergeDoc::OnUpdateFileSave(CCmdUI* pCmdUI)
 {
-       BOOL bModified = FALSE;
+       bool bModified = false;
        for (int nBuffer = 0; nBuffer < m_nBuffers; nBuffer++)
                bModified |= m_pView[nBuffer]->GetModified();
        pCmdUI->Enable(bModified);
@@ -682,64 +698,16 @@ void CHexMergeDoc::OnFileReload()
        if (!PromptAndSaveIfNeeded(true))
                return;
        
+       FileLocation fileloc[3];
        bool bRO[3];
        for (int pane = 0; pane < m_nBuffers; pane++)
        {
-               bRO[pane] = !!m_pView[pane]->GetReadOnly();
-               theApp.m_strDescriptions[pane] = m_strDesc[pane];
-       }
-       int nActivePane = GetActiveMergeView()->m_nThisPane;
-       OpenDocs(m_filePaths, bRO);
-}
-
-/**
- * @brief Copy selected bytes from source view to destination view
- * @note Grows destination buffer as appropriate
- */
-void CHexMergeDoc::CopySel(CHexMergeView *pViewSrc, CHexMergeView *pViewDst)
-{
-       const IHexEditorWindow::Status *pStatSrc = pViewSrc->GetStatus();
-       int i = min(pStatSrc->iStartOfSelection, pStatSrc->iEndOfSelection);
-       int j = max(pStatSrc->iStartOfSelection, pStatSrc->iEndOfSelection);
-       int u = pViewSrc->GetLength();
-       int v = pViewDst->GetLength();
-       if (pStatSrc->bSelected && i <= v)
-       {
-               if (v <= j)
-                       v = j + 1;
-               BYTE *p = pViewSrc->GetBuffer(u);
-               BYTE *q = pViewDst->GetBuffer(v);
-               memcpy(q + i, p + i, j - i + 1);
-               CWnd *pwndFocus = CWnd::GetFocus();
-               if (pwndFocus != pViewSrc)
-                       pViewDst->RepaintRange(i, j);
-               if (pwndFocus != pViewDst)
-                       pViewSrc->RepaintRange(i, j);
-               pViewDst->SetModified(TRUE);
-       }
-}
-
-/**
- * @brief Copy all bytes from source view to destination view
- * @note Grows destination buffer as appropriate
- */
-void CHexMergeDoc::CopyAll(CHexMergeView *pViewSrc, CHexMergeView *pViewDst)
-{
-       if (int i = pViewSrc->GetLength())
-       {
-               int j = pViewDst->GetLength();
-               BYTE *p = pViewSrc->GetBuffer(i);
-               BYTE *q = pViewDst->GetBuffer(max(i, j));
-               if (q == 0)
-                       AfxThrowMemoryException();
-               memcpy(q, p, i);
-               CWnd *pwndFocus = CWnd::GetFocus();
-               if (pwndFocus != pViewSrc)
-                       pViewDst->RepaintRange(0, i);
-               if (pwndFocus != pViewDst)
-                       pViewSrc->RepaintRange(0, i);
-               pViewDst->SetModified(TRUE);
+               fileloc[pane].setPath(m_filePaths[pane]);
+               bRO[pane] = m_pView[pane]->GetReadOnly();
        }
+       if (!OpenDocs(m_nBuffers, fileloc, bRO, m_strDesc))
+               return;
+       MoveOnLoad(GetActiveMergeView()->m_nThisPane);
 }
 
 /**
@@ -749,7 +717,7 @@ void CHexMergeDoc::OnL2r()
 {
        int dstPane = (GetActiveMergeView()->m_nThisPane < m_nBuffers - 1) ? GetActiveMergeView()->m_nThisPane + 1 : m_nBuffers - 1;
        int srcPane = dstPane - 1;
-       CopySel(m_pView[srcPane], m_pView[dstPane]);
+       CHexMergeView::CopySel(m_pView[srcPane], m_pView[dstPane]);
 }
 
 /**
@@ -759,7 +727,7 @@ void CHexMergeDoc::OnR2l()
 {
        int dstPane = (GetActiveMergeView()->m_nThisPane > 0) ? GetActiveMergeView()->m_nThisPane - 1 : 0;
        int srcPane = dstPane + 1;
-       CopySel(m_pView[srcPane], m_pView[dstPane]);
+       CHexMergeView::CopySel(m_pView[srcPane], m_pView[dstPane]);
 }
 
 /**
@@ -769,7 +737,7 @@ void CHexMergeDoc::OnCopyFromLeft()
 {
        int dstPane = GetActiveMergeView()->m_nThisPane;
        int srcPane = (dstPane - 1 < 0) ? 0 : dstPane - 1;
-       CopySel(m_pView[srcPane], m_pView[dstPane]);
+       CHexMergeView::CopySel(m_pView[srcPane], m_pView[dstPane]);
 }
 
 /**
@@ -779,7 +747,7 @@ void CHexMergeDoc::OnCopyFromRight()
 {
        int dstPane = GetActiveMergeView()->m_nThisPane;
        int srcPane = (dstPane + 1 > m_nBuffers - 1) ? m_nBuffers - 1 : dstPane + 1;
-       CopySel(m_pView[srcPane], m_pView[dstPane]);
+       CHexMergeView::CopySel(m_pView[srcPane], m_pView[dstPane]);
 }
 
 /**
@@ -789,7 +757,7 @@ void CHexMergeDoc::OnAllRight()
 {
        int dstPane = (GetActiveMergeView()->m_nThisPane < m_nBuffers - 1) ? GetActiveMergeView()->m_nThisPane + 1 : m_nBuffers - 1;
        int srcPane = dstPane - 1;
-       CopyAll(m_pView[srcPane], m_pView[dstPane]);
+       CHexMergeView::CopyAll(m_pView[srcPane], m_pView[dstPane]);
 }
 
 /**
@@ -799,7 +767,7 @@ void CHexMergeDoc::OnAllLeft()
 {
        int dstPane = (GetActiveMergeView()->m_nThisPane > 0) ? GetActiveMergeView()->m_nThisPane - 1 : 0;
        int srcPane = dstPane + 1;
-       CopyAll(m_pView[srcPane], m_pView[dstPane]);
+       CHexMergeView::CopyAll(m_pView[srcPane], m_pView[dstPane]);
 }
 
 /**
@@ -828,3 +796,36 @@ void CHexMergeDoc::OnViewZoomNormal()
        for (int pane = 0; pane < m_nBuffers; pane++)
                m_pView[pane]->ZoomText(0);
 }
+
+void CHexMergeDoc::OnRefresh()
+{
+       if (UpdateDiffItem(m_pDirDoc) == 0)
+       {
+               CMergeFrameCommon::ShowIdenticalMessage(m_filePaths, true,
+                       [](LPCTSTR msg, UINT flags, UINT id) -> int { return AfxMessageBox(msg, flags, id); });
+       }
+}
+
+void CHexMergeDoc::OnFileRecompareAs(UINT nID)
+{
+       FileLocation fileloc[3];
+       DWORD dwFlags[3];
+       String strDesc[3];
+       int nBuffers = m_nBuffers;
+       CDirDoc *pDirDoc = m_pDirDoc->GetMainView() ? m_pDirDoc : 
+               static_cast<CDirDoc*>(theApp.m_pDirTemplate->CreateNewDocument());
+       for (int nBuffer = 0; nBuffer < nBuffers; ++nBuffer)
+       {
+               fileloc[nBuffer].setPath(m_filePaths[nBuffer]);
+               dwFlags[nBuffer] = m_pView[nBuffer]->GetReadOnly() ? FFILEOPEN_READONLY : 0;
+               strDesc[nBuffer] = m_strDesc[nBuffer];
+       }
+       CloseNow();
+       GetMainFrame()->ShowMergeDoc(nID, pDirDoc, nBuffers, fileloc, dwFlags, strDesc);
+}
+
+void CHexMergeDoc::OnUpdateFileRecompareAs(CCmdUI* pCmdUI)
+{
+       pCmdUI->Enable(pCmdUI->m_nID != ID_MERGE_COMPARE_XML);
+}
+