OSDN Git Service

theApp is unnecessary because these methods are a static methods
[winmerge-jp/winmerge-jp.git] / Src / HexMergeView.cpp
index 39e7ff7..f5a3114 100644 (file)
@@ -2,30 +2,14 @@
 //    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  HexMergeView.cpp
  *
- * @brief Implementation file for CHexMergeDoc
+ * @brief Implementation file for CHexMergeView
  *
  */
-// ID line follows -- this is updated by SVN
-// $Id: HexMergeView.cpp 7165 2010-05-15 14:04:43Z jtuc $
 
 #include "stdafx.h"
 #include "HexMergeFrm.h"
 
 #ifdef _DEBUG
 #define new DEBUG_NEW
-#undef THIS_FILE
-static char THIS_FILE[] = __FILE__;
 #endif
 
+/** @brief Location for hex compare specific help to open. */
+static TCHAR HexMergeViewHelpLocation[] = _T("::/htmlhelp/Compare_bin.html");
+
 /**
  * @brief Turn bool api result into success/error code
  */
@@ -50,8 +35,8 @@ static HRESULT NTAPI SE(BOOL f)
        if (f)
                return S_OK;
        HRESULT hr = (HRESULT)::GetLastError();
-       ASSERT(hr);
-       if (hr == 0)
+       ASSERT(hr != NULL);
+       if (hr == NULL)
                hr = E_UNEXPECTED;
        return hr;
 }
@@ -78,10 +63,16 @@ BEGIN_MESSAGE_MAP(CHexMergeView, CView)
        ON_WM_CREATE()
        ON_WM_HSCROLL()
        ON_WM_VSCROLL()
+       ON_WM_MOUSEWHEEL()
        ON_WM_NCCALCSIZE()
+       ON_COMMAND(ID_HELP, OnHelp)
        ON_COMMAND(ID_EDIT_FIND, OnEditFind)
        ON_COMMAND(ID_EDIT_REPLACE, OnEditReplace)
        ON_COMMAND(ID_EDIT_REPEAT, OnEditRepeat)
+       ON_UPDATE_COMMAND_UI(ID_EDIT_UNDO, OnUpdateEditUndo)
+       ON_COMMAND(ID_EDIT_UNDO, OnEditUndo)
+       ON_UPDATE_COMMAND_UI(ID_EDIT_REDO, OnUpdateEditRedo)
+       ON_COMMAND(ID_EDIT_REDO, OnEditRedo)
        ON_COMMAND(ID_EDIT_CUT, OnEditCut)
        ON_COMMAND(ID_EDIT_COPY, OnEditCopy)
        ON_COMMAND(ID_EDIT_PASTE, OnEditPaste)
@@ -103,9 +94,8 @@ END_MESSAGE_MAP()
  * @brief Constructor.
  */
 CHexMergeView::CHexMergeView()
-: m_pif(0)
+: m_pif(nullptr)
 , m_nThisPane(0)
-, m_mtime(0)
 {
 }
 
@@ -114,26 +104,29 @@ CHexMergeView::CHexMergeView()
  */
 void CHexMergeView::OnDraw(CDC *)
 {
-       ASSERT(FALSE);
+       ASSERT(false);
 }
 
 /**
- * @brief Load heksedit.dll and setup window class name
+ * @brief returns true if heksedit.dll is loadable
  */
-BOOL CHexMergeView::PreCreateWindow(CREATESTRUCT& cs)
+bool CHexMergeView::IsLoadable()
 {
-       static void *pv = NULL;
-       if (pv == NULL)
+       static void *pv = nullptr;
+       if (pv == nullptr)
        {
-               static const CLSID clsid = { 0xBCA3CA6B, 0xCC6B, 0x4F79,
-                       { 0xA2, 0xC2, 0xDD, 0xBE, 0x86, 0x4B, 0x1C, 0x90 } };
-               if (FAILED(::CoGetClassObject(clsid, CLSCTX_INPROC_SERVER, NULL, IID_IUnknown, &pv)))
-               {
-                       pv = LoadLibrary(_T("Frhed\\hekseditU.dll"));
-                       if (!pv)
-                               LangMessageBox(IDS_FRHED_NOTINSTALLED, MB_OK);
-               }
+               pv = LoadLibrary(_T("Frhed\\hekseditU.dll"));
        }
+       return pv != nullptr;
+}
+
+/**
+ * @brief Load heksedit.dll and setup window class name
+ */
+BOOL CHexMergeView::PreCreateWindow(CREATESTRUCT& cs)
+{
+       if (!IsLoadable())
+               LangMessageBox(IDS_FRHED_NOTINSTALLED, MB_OK);
        cs.lpszClass = _T("heksedit");
        cs.style |= WS_HSCROLL | WS_VSCROLL;
        return TRUE;
@@ -147,7 +140,7 @@ int CHexMergeView::OnCreate(LPCREATESTRUCT lpCreateStruct)
        if (CView::OnCreate(lpCreateStruct) == -1)
                return -1;
        m_pif = reinterpret_cast<IHexEditorWindow *>(::GetWindowLongPtr(m_hWnd, GWLP_USERDATA));
-       if (m_pif == 0 || m_pif->get_interface_version() < HEKSEDIT_INTERFACE_VERSION)
+       if (m_pif == nullptr || m_pif->get_interface_version() < HEKSEDIT_INTERFACE_VERSION)
                return -1;
        return 0;
 }
@@ -172,19 +165,24 @@ void CHexMergeView::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar * pScrollBar)
                SetScrollInfo(SB_HORZ, &si);
        }
        CView::OnHScroll(nSBCode, nPos, pScrollBar);
-       if (pScrollBar)
+       if (pScrollBar != nullptr)
        {
                GetScrollInfo(SB_HORZ, &si, SIF_ALL | SIF_DISABLENOSCROLL);
                if (nSBCode != SB_THUMBTRACK)
                {
                        pScrollBar->SetScrollInfo(&si);
                }
-               CSplitterWndEx *pSplitter = (CSplitterWndEx *)GetParentSplitter(this, TRUE);
-               int nID = GetDlgCtrlID();
-               nID ^= pSplitter->IdFromRowCol(0, 0) ^ pSplitter->IdFromRowCol(0, 1);
-               CWnd *pWnd = pSplitter->GetDlgItem(nID);
-               pWnd->SetScrollInfo(SB_HORZ, &si);
-               pWnd->SendMessage(WM_HSCROLL, MAKEWPARAM(nSBCode, nPos));
+               
+               CSplitterWndEx *pSplitter = static_cast<CSplitterWndEx *>(GetParentSplitter(this, TRUE));
+               for (int pane = 0; pane < pSplitter->GetColumnCount(); ++pane)
+               {
+                       if (pane != m_nThisPane)
+                       {
+                               CWnd *pWnd = pSplitter->GetDlgItem(pSplitter->IdFromRowCol(0, pane));
+                               pWnd->SetScrollInfo(SB_HORZ, &si);
+                               pWnd->SendMessage(WM_HSCROLL, MAKEWPARAM(nSBCode, nPos));
+                       }
+               }
        }
 }
 
@@ -208,6 +206,16 @@ void CHexMergeView::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar * pScrollBar)
        }
 }
 
+BOOL CHexMergeView::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
+{
+       if ((GetAsyncKeyState(VK_CONTROL) &0x8000) != 0) // if (nFlags & MK_CONTROL)
+       {
+               PostMessage(WM_COMMAND, zDelta < 0 ? ID_VIEW_ZOOMOUT : ID_VIEW_ZOOMIN);
+               return 1;
+       }
+       return 0;
+}
+
 /**
  * @brief Synchronize file path bar activation states
  */
@@ -237,25 +245,21 @@ int CHexMergeView::GetLength()
 /**
  * @brief Checks if file has changed since last update
  * @param [in] path File to check
- * @return TRUE if file is changed.
+ * @return `true` if file is changed.
  */
-BOOL CHexMergeView::IsFileChangedOnDisk(LPCTSTR path)
+IMergeDoc::FileChange CHexMergeView::IsFileChangedOnDisk(LPCTSTR path)
 {
-       // NB: FileTimes are measured in 100 nanosecond intervals since 1601-01-01.
-       BOOL bChanged = FALSE;
-       HANDLE h = CreateFile(path, FILE_READ_ATTRIBUTES, FILE_SHARE_READ|FILE_SHARE_WRITE,
-               0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
-       if (h != INVALID_HANDLE_VALUE)
-       {
-               UINT64 mtime = GetLastWriteTime(h);
-               UINT64 lower = min(mtime, m_mtime);
-               UINT64 upper = max(mtime, m_mtime);
-               BOOL bIgnoreSmallDiff = GetOptionsMgr()->GetBool(OPT_IGNORE_SMALL_FILETIME);
-               UINT64 tolerance = bIgnoreSmallDiff ? SmallTimeDiff * 10000000 : 0;
-               bChanged = upper - lower > tolerance || m_size != GetFileSize(h, 0);
-               CloseHandle(h);
-       }
-       return bChanged;
+       DiffFileInfo dfi;
+       if (!dfi.Update(path))
+               return IMergeDoc::FileChange::Removed;
+       int tolerance = 0;
+       if (GetOptionsMgr()->GetBool(OPT_IGNORE_SMALL_FILETIME))
+               tolerance = SmallTimeDiff; // From MainFrm.h
+       int64_t timeDiff = dfi.mtime - m_fileInfo.mtime;
+       if (timeDiff < 0) timeDiff = -timeDiff;
+       if ((timeDiff > tolerance * Poco::Timestamp::resolution()) || (dfi.size != m_fileInfo.size))
+               return IMergeDoc::FileChange::Changed;
+       return IMergeDoc::FileChange::NoChange;
 }
 
 /**
@@ -267,10 +271,9 @@ HRESULT CHexMergeView::LoadFile(LPCTSTR path)
                FILE_SHARE_READ | FILE_SHARE_WRITE,
                0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
        HRESULT hr = SE(h != INVALID_HANDLE_VALUE);
-       if (hr != S_OK)
+       if (h == INVALID_HANDLE_VALUE)
                return hr;
-       m_mtime = GetLastWriteTime(h);
-       DWORD length = m_size = GetFileSize(h, 0);
+       DWORD length = GetFileSize(h, 0);
        hr = SE(length != INVALID_FILE_SIZE);
        if (hr == S_OK)
        {
@@ -287,6 +290,7 @@ HRESULT CHexMergeView::LoadFile(LPCTSTR path)
                }
        }
        CloseHandle(h);
+       m_fileInfo.Update(path);
        return hr;
 }
 
@@ -296,83 +300,85 @@ HRESULT CHexMergeView::LoadFile(LPCTSTR path)
 HRESULT CHexMergeView::SaveFile(LPCTSTR path)
 {
        // Warn user in case file has been changed by someone else
-       if (IsFileChangedOnDisk(path))
+       if (IsFileChangedOnDisk(path) == IMergeDoc::FileChange::Changed)
        {
-               String msg = string_format_string1(_("Another application has updated file\n%1\nsince WinMerge loaded it.\n\nOverwrite changed file?"), path);
+               String msg = strutils::format_string1(_("Another application has updated file\n%1\nsince WinMerge loaded it.\n\nOverwrite changed file?"), path);
                if (AfxMessageBox(msg.c_str(), MB_ICONWARNING | MB_YESNO) == IDNO)
                        return S_OK;
        }
        // Ask user what to do about FILE_ATTRIBUTE_READONLY
        String strPath = path;
-       BOOL bApplyToAll = FALSE;
-       if (theApp.HandleReadonlySave(strPath, FALSE, bApplyToAll) == IDCANCEL)
+       bool bApplyToAll = false;
+       if (CMergeApp::HandleReadonlySave(strPath, false, bApplyToAll) == IDCANCEL)
                return S_OK;
        path = strPath.c_str();
        // Take a chance to create a backup
-       if (!theApp.CreateBackup(FALSE, path))
+       if (!CMergeApp::CreateBackup(false, path))
                return S_OK;
        // Write data to an intermediate file
-       String tempPath = env_GetTempPath();
-       String sIntermediateFilename = env_GetTempFileName(tempPath, _T("MRG_"), 0);
+       String tempPath = env::GetTemporaryPath();
+       String sIntermediateFilename = env::GetTemporaryFileName(tempPath, _T("MRG_"), 0);
        if (sIntermediateFilename.empty())
                return E_FAIL; //Nothing to do if even tempfile name fails
        HANDLE h = CreateFile(sIntermediateFilename.c_str(), GENERIC_WRITE, FILE_SHARE_READ,
                0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
        HRESULT hr = SE(h != INVALID_HANDLE_VALUE);
-       if (hr != S_OK)
+       if (h == INVALID_HANDLE_VALUE)
                return hr;
        DWORD length = GetLength();
        void *buffer = GetBuffer(length);
        if (buffer == 0)
+       {
+               CloseHandle(h);
                return E_POINTER;
+       }
        DWORD cb = 0;
        hr = SE(WriteFile(h, buffer, length, &cb, 0) && cb == length);
-       UINT64 mtime = GetLastWriteTime(h);
        CloseHandle(h);
        if (hr != S_OK)
                return hr;
        hr = SE(CopyFile(sIntermediateFilename.c_str(), path, FALSE));
        if (hr != S_OK)
                return hr;
-       m_mtime = mtime;
-       SetModified(FALSE);
+       m_fileInfo.Update(path);
+       SetSavePoint();
        hr = SE(DeleteFile(sIntermediateFilename.c_str()));
        if (hr != S_OK)
        {
-               LogErrorString(string_format(_T("DeleteFile(%s) failed: %s"),
-                       sIntermediateFilename.c_str(), GetSysError(hr).c_str()));
+               LogErrorString(strutils::format(_T("DeleteFile(%s) failed: %s"),
+                       sIntermediateFilename, GetSysError(hr)));
        }
        return S_OK;
 }
 
 /**
- * @brief Get status
+ * @brief Get modified flag
  */
-IHexEditorWindow::Status *CHexMergeView::GetStatus()
+bool CHexMergeView::GetModified()
 {
-       return m_pif->get_status();
+       return m_pif->get_status()->iFileChanged != 0;
 }
 
 /**
- * @brief Get modified flag
+ * @brief Set modified flag
  */
-BOOL CHexMergeView::GetModified()
+void CHexMergeView::SetSavePoint()
 {
-       return m_pif->get_status()->iFileChanged;
+       m_pif->set_savepoint();
 }
 
 /**
- * @brief Set modified flag
+ * @brief Clear undo records
  */
-void CHexMergeView::SetModified(BOOL bModified)
+void CHexMergeView::ClearUndoRecords()
 {
-       m_pif->get_status()->iFileChanged = bModified;
+       m_pif->clear_undorecords();
 }
 
 /**
  * @brief Get readonly flag
  */
-BOOL CHexMergeView::GetReadOnly()
+bool CHexMergeView::GetReadOnly()
 {
        return m_pif->get_settings()->bReadOnly;
 }
@@ -380,7 +386,7 @@ BOOL CHexMergeView::GetReadOnly()
 /**
  * @brief Set readonly flag
  */
-void CHexMergeView::SetReadOnly(BOOL bReadOnly)
+void CHexMergeView::SetReadOnly(bool bReadOnly)
 {
        m_pif->get_settings()->bReadOnly = bReadOnly;
 }
@@ -395,15 +401,6 @@ void CHexMergeView::ResizeWindow()
 }
 
 /**
- * @brief Repaint a range of bytes
- */
-void CHexMergeView::RepaintRange(int i, int j)
-{
-       int iBytesPerLine = m_pif->get_settings()->iBytesPerLine;
-       m_pif->repaint(i / iBytesPerLine, j / iBytesPerLine);
-}
-
-/**
  * @brief Find a sequence of bytes
  */
 void CHexMergeView::OnEditFind()
@@ -431,6 +428,38 @@ void CHexMergeView::OnEditRepeat()
 }
 
 /**
+* @brief Called when "Undo" item is updated
+*/
+void CHexMergeView::OnUpdateEditUndo(CCmdUI* pCmdUI)
+{
+       pCmdUI->Enable(m_pif->can_undo());
+}
+
+/**
+ * @brief Undo last action
+ */
+void CHexMergeView::OnEditUndo()
+{
+       m_pif->CMD_edit_undo();
+}
+
+/**
+* @brief Called when "Redo" item is updated
+*/
+void CHexMergeView::OnUpdateEditRedo(CCmdUI* pCmdUI)
+{
+       pCmdUI->Enable(m_pif->can_redo());
+}
+
+/**
+ * @brief Redo last action
+ */
+void CHexMergeView::OnEditRedo()
+{
+       m_pif->CMD_edit_redo();
+}
+
+/**
  * @brief Cut selected content
  */
 void CHexMergeView::OnEditCut()
@@ -480,7 +509,7 @@ BOOL CHexMergeView::PreTranslateMessage(MSG* pMsg)
        if (pMsg->message == WM_KEYDOWN)
        {
                // Close window in response to VK_ESCAPE if user has allowed it from options
-               if (pMsg->wParam == VK_ESCAPE && GetOptionsMgr()->GetBool(OPT_CLOSE_WITH_ESC))
+               if (pMsg->wParam == VK_ESCAPE && GetOptionsMgr()->GetInt(OPT_CLOSE_WITH_ESC) != 0)
                {
                        GetParentFrame()->PostMessage(WM_CLOSE, 0, 0);
                        return TRUE;
@@ -521,7 +550,32 @@ void CHexMergeView::OnPrevdiff()
        m_pif->select_prev_diff(FALSE);
 }
 
+/** @brief Open help from mainframe when user presses F1*/
+void CHexMergeView::OnHelp()
+{
+       theApp.ShowHelp(HexMergeViewHelpLocation);
+}
+
 void CHexMergeView::ZoomText(int amount)
 {
        m_pif->CMD_zoom(amount);
 }
+
+/**
+ * @brief Copy selected bytes from source view to destination view
+ * @note Grows destination buffer as appropriate
+ */
+void CHexMergeView::CopySel(const CHexMergeView *src, CHexMergeView *dst)
+{
+       dst->m_pif->copy_sel_from(src->m_pif);
+}
+
+/**
+ * @brief Copy all bytes from source view to destination view
+ * @note Grows destination buffer as appropriate
+ */
+void CHexMergeView::CopyAll(const CHexMergeView *src, CHexMergeView *dst)
+{
+       dst->m_pif->copy_all_from(src->m_pif);
+}
+