1 /////////////////////////////////////////////////////////////////////////////
2 // WinMerge: an interactive diff/merge utility
3 // Copyright (C) 1997-2000 Thingamahoochie Software
5 // SPDX-License-Identifier: GPL-2.0-or-later
6 /////////////////////////////////////////////////////////////////////////////
8 * @file HexMergeDoc.cpp
10 * @brief Implementation file for CHexMergeDoc
15 #include "HexMergeDoc.h"
17 #include "UnicodeString.h"
18 #include "HexMergeFrm.h"
19 #include "HexMergeView.h"
21 #include "FolderCmp.h"
22 #include "DiffContext.h" // FILE_SAME
24 #include "DirActions.h"
25 #include "OptionsDef.h"
26 #include "DiffFileInfo.h"
27 #include "SaveClosingDlg.h"
28 #include "SelectPluginDlg.h"
31 #include "OptionsMgr.h"
32 #include "FileOrFolderSelect.h"
33 #include "DiffWrapper.h"
34 #include "SyntaxColors.h"
36 #include "Constants.h"
43 int CHexMergeDoc::m_nBuffersTemp = 2;
45 static void UpdateDiffItem(int nBuffers, DIFFITEM &di, CDiffContext *pCtxt);
46 static int Try(HRESULT hr, UINT type = MB_OKCANCEL|MB_ICONSTOP);
49 * @brief Update diff item
51 static void UpdateDiffItem(int nBuffers, DIFFITEM &di, CDiffContext *pCtxt)
53 di.diffcode.setSideNone();
54 for (int nBuffer = 0; nBuffer < nBuffers; nBuffer++)
56 di.diffFileInfo[nBuffer].ClearPartial();
57 if (pCtxt->UpdateInfoFromDiskHalf(di, nBuffer))
58 di.diffcode.diffcode |= DIFFCODE::FIRST << nBuffer;
61 di.diffcode.diffcode &= ~(DIFFCODE::TEXTFLAGS | DIFFCODE::COMPAREFLAGS | DIFFCODE::COMPAREFLAGS3WAY);
63 FolderCmp folderCmp(pCtxt);
64 di.diffcode.diffcode |= folderCmp.prepAndCompareFiles(di);
68 * @brief Issue an error popup if passed in HRESULT is nonzero
70 static int Try(HRESULT hr, UINT type)
72 return hr ? CInternetException(hr).ReportError(type) : 0;
75 /////////////////////////////////////////////////////////////////////////////
78 IMPLEMENT_DYNCREATE(CHexMergeDoc, CDocument)
80 BEGIN_MESSAGE_MAP(CHexMergeDoc, CDocument)
81 //{{AFX_MSG_MAP(CHexMergeDoc)
82 ON_COMMAND(ID_FILE_SAVE, OnFileSave)
83 ON_COMMAND(ID_FILE_SAVE_LEFT, OnFileSaveLeft)
84 ON_COMMAND(ID_FILE_SAVE_RIGHT, OnFileSaveRight)
85 ON_COMMAND(ID_FILE_SAVEAS_LEFT, OnFileSaveAsLeft)
86 ON_COMMAND(ID_FILE_SAVEAS_RIGHT, OnFileSaveAsRight)
87 ON_UPDATE_COMMAND_UI(ID_STATUS_DIFFNUM, OnUpdateStatusNum)
88 ON_UPDATE_COMMAND_UI(ID_FILE_SAVE_LEFT, OnUpdateFileSaveLeft)
89 ON_UPDATE_COMMAND_UI(ID_FILE_SAVE_RIGHT, OnUpdateFileSaveRight)
90 ON_UPDATE_COMMAND_UI(ID_FILE_SAVE, OnUpdateFileSave)
91 ON_COMMAND(ID_RESCAN, OnFileReload)
92 ON_COMMAND(ID_L2R, OnL2r)
93 ON_COMMAND(ID_R2L, OnR2l)
94 ON_COMMAND(ID_COPY_FROM_LEFT, OnCopyFromLeft)
95 ON_COMMAND(ID_COPY_FROM_RIGHT, OnCopyFromRight)
96 ON_COMMAND(ID_ALL_LEFT, OnAllLeft)
97 ON_COMMAND(ID_ALL_RIGHT, OnAllRight)
98 ON_COMMAND(ID_VIEW_ZOOMIN, OnViewZoomIn)
99 ON_COMMAND(ID_VIEW_ZOOMOUT, OnViewZoomOut)
100 ON_COMMAND(ID_VIEW_ZOOMNORMAL, OnViewZoomNormal)
101 ON_COMMAND(ID_REFRESH, OnRefresh)
102 ON_COMMAND_RANGE(ID_MERGE_COMPARE_TEXT, ID_MERGE_COMPARE_IMAGE, OnFileRecompareAs)
103 ON_COMMAND_RANGE(ID_UNPACKERS_FIRST, ID_UNPACKERS_LAST, OnFileRecompareAs)
104 ON_UPDATE_COMMAND_UI_RANGE(ID_MERGE_COMPARE_TEXT, ID_MERGE_COMPARE_IMAGE, OnUpdateFileRecompareAs)
105 ON_COMMAND(ID_OPEN_WITH_UNPACKER, OnOpenWithUnpacker)
109 /////////////////////////////////////////////////////////////////////////////
110 // CHexMergeDoc construction/destruction
113 * @brief Constructor.
115 CHexMergeDoc::CHexMergeDoc()
117 , m_nBuffers(m_nBuffersTemp)
119 , m_nBufferType{BUFFERTYPE::NORMAL, BUFFERTYPE::NORMAL, BUFFERTYPE::NORMAL}
121 m_filePaths.SetSize(m_nBuffers);
127 * Informs associated dirdoc that mergedoc is closing.
129 CHexMergeDoc::~CHexMergeDoc()
131 if (m_pDirDoc != nullptr)
132 m_pDirDoc->MergeDocClosing(this);
136 * @brief Return active merge edit view (or left one if neither active)
138 CHexMergeView * CHexMergeDoc::GetActiveMergeView() const
140 CView * pActiveView = GetParentFrame()->GetActiveView();
141 CHexMergeView * pHexMergeView = dynamic_cast<CHexMergeView *>(pActiveView);
142 if (pHexMergeView == nullptr)
143 pHexMergeView = m_pView[0]; // default to left view (in case some location or detail view active)
144 return pHexMergeView;
148 * @brief Update associated diff item
150 int CHexMergeDoc::UpdateDiffItem(CDirDoc *pDirDoc)
152 // If directory compare has results
153 if (pDirDoc != nullptr && pDirDoc->HasDiffs())
155 CDiffContext &ctxt = pDirDoc->GetDiffContext();
156 if (DIFFITEM *pos = FindItemFromPaths(ctxt, m_filePaths))
158 DIFFITEM &di = ctxt.GetDiffRefAt(pos);
159 ::UpdateDiffItem(m_nBuffers, di, &ctxt);
163 int lengthFirst = m_pView[0]->GetLength();
164 void *bufferFirst = m_pView[0]->GetBuffer(lengthFirst);
165 for (int nBuffer = 1; nBuffer < m_nBuffers; nBuffer++)
167 int length = m_pView[nBuffer]->GetLength();
168 if (lengthFirst != length)
172 void *buffer = m_pView[nBuffer]->GetBuffer(length);
173 bDiff = (memcmp(bufferFirst, buffer, lengthFirst) != 0);
178 GetParentFrame()->SetLastCompareResult(bDiff);
179 return bDiff ? 1 : 0;
183 * @brief Asks and then saves modified files
185 bool CHexMergeDoc::PromptAndSaveIfNeeded(bool bAllowCancel)
187 bool bLModified = false, bMModified = false, bRModified = false;
191 bLModified = m_pView[0]->GetModified();
192 bMModified = m_pView[1]->GetModified();
193 bRModified = m_pView[2]->GetModified();
197 bLModified = m_pView[0]->GetModified();
198 bRModified = m_pView[1]->GetModified();
200 if (!bLModified && !bMModified && !bRModified)
203 const String &pathLeft = m_filePaths.GetLeft();
204 const String &pathMiddle = m_filePaths.GetMiddle();
205 const String &pathRight = m_filePaths.GetRight();
208 bool bLSaveSuccess = false, bMSaveSuccess = false, bRSaveSuccess = false;
211 dlg.DoAskFor(bLModified, bMModified, bRModified);
213 dlg.m_bDisableCancel = true;
214 if (!pathLeft.empty())
215 dlg.m_sLeftFile = pathLeft;
217 dlg.m_sLeftFile = m_strDesc[0];
220 if (!pathMiddle.empty())
221 dlg.m_sMiddleFile = pathMiddle;
223 dlg.m_sMiddleFile = m_strDesc[1];
225 if (!pathRight.empty())
226 dlg.m_sRightFile = pathRight;
228 dlg.m_sRightFile = m_strDesc[1];
230 if (dlg.DoModal() == IDOK)
234 if (dlg.m_leftSave == SaveClosingDlg::SAVECLOSING_SAVE)
236 bLSaveSuccess = DoFileSave(0);
242 m_pView[0]->SetSavePoint();
247 if (dlg.m_middleSave == SaveClosingDlg::SAVECLOSING_SAVE)
249 bMSaveSuccess = DoFileSave(1);
255 m_pView[1]->SetSavePoint();
260 if (dlg.m_rightSave == SaveClosingDlg::SAVECLOSING_SAVE)
262 bRSaveSuccess = DoFileSave(m_nBuffers - 1);
268 m_pView[m_nBuffers - 1]->SetSavePoint();
277 // If file were modified and saving was successfull,
278 // update status on dir view
279 if (bLSaveSuccess || bMSaveSuccess || bRSaveSuccess)
281 UpdateDiffItem(m_pDirDoc);
288 * @brief Save modified documents
290 BOOL CHexMergeDoc::SaveModified()
292 return PromptAndSaveIfNeeded(true);
296 * @brief Saves both files
298 void CHexMergeDoc::OnFileSave()
300 for (int nBuffer = 0; nBuffer < m_nBuffers; nBuffer++)
304 bool CHexMergeDoc::DoFileSave(int nBuffer)
307 if (m_pView[nBuffer]->GetModified())
309 if (m_nBufferType[nBuffer] == BUFFERTYPE::UNNAMED)
310 result = DoFileSaveAs(nBuffer);
313 const String &path = m_filePaths.GetPath(nBuffer);
314 HRESULT hr = m_pView[nBuffer]->SaveFile(path.c_str());
315 if (Try(hr) == IDCANCEL)
318 return DoFileSaveAs(nBuffer);
321 UpdateDiffItem(m_pDirDoc);
327 bool CHexMergeDoc::DoFileSaveAs(int nBuffer, bool packing)
329 const String &path = m_filePaths.GetPath(nBuffer);
333 title = _("Save Left File As");
334 else if (nBuffer == m_nBuffers - 1)
335 title = _("Save Right File As");
337 title = _("Save Middle File As");
338 if (SelectFile(AfxGetMainWnd()->GetSafeHwnd(), strPath, false, path.c_str(), title))
340 HRESULT hr = m_pView[nBuffer]->SaveFile(strPath.c_str());
341 if (Try(hr) == IDCANCEL)
347 // We are saving scratchpad (unnamed file)
348 m_nBufferType[nBuffer] = BUFFERTYPE::UNNAMED_SAVED;
349 m_strDesc[nBuffer].erase();
352 m_filePaths.SetPath(nBuffer, strPath);
353 UpdateDiffItem(m_pDirDoc);
354 UpdateHeaderPath(nBuffer);
361 * @brief Saves left-side file
363 void CHexMergeDoc::OnFileSaveLeft()
369 * @brief Saves middle-side file
371 void CHexMergeDoc::OnFileSaveMiddle()
377 * @brief Saves right-side file
379 void CHexMergeDoc::OnFileSaveRight()
381 DoFileSave(m_nBuffers - 1);
385 * @brief Saves left-side file with name asked
387 void CHexMergeDoc::OnFileSaveAsLeft()
393 * @brief Saves right-side file with name asked
395 void CHexMergeDoc::OnFileSaveAsMiddle()
401 * @brief Saves right-side file with name asked
403 void CHexMergeDoc::OnFileSaveAsRight()
405 DoFileSaveAs(m_nBuffers - 1);
409 * @brief Update diff-number pane text
411 void CHexMergeDoc::OnUpdateStatusNum(CCmdUI* pCmdUI)
414 pCmdUI->SetText(s.c_str());
418 * @brief DirDoc gives us its identity just after it creates us
420 void CHexMergeDoc::SetDirDoc(CDirDoc * pDirDoc)
422 ASSERT(pDirDoc != nullptr && m_pDirDoc == nullptr);
426 bool CHexMergeDoc::GetReadOnly(int nBuffer) const
428 return m_pView[nBuffer]->GetReadOnly();
432 * @brief Return pointer to parent frame
434 CHexMergeFrame * CHexMergeDoc::GetParentFrame() const
436 return static_cast<CHexMergeFrame *>(m_pView[0]->GetParentFrame());
440 * @brief DirDoc is closing
442 void CHexMergeDoc::DirDocClosing(CDirDoc * pDirDoc)
444 ASSERT(m_pDirDoc == pDirDoc);
449 * @brief DirDoc commanding us to close
451 bool CHexMergeDoc::CloseNow()
453 // Allow user to cancel closing
454 if (!PromptAndSaveIfNeeded(true))
457 GetParentFrame()->DestroyWindow();
462 * @brief Load one file
464 HRESULT CHexMergeDoc::LoadOneFile(int index, LPCTSTR filename, bool readOnly, const String& strDesc)
468 if (Try(m_pView[index]->LoadFile(filename), MB_ICONSTOP) != 0)
470 m_pView[index]->SetReadOnly(readOnly);
471 m_filePaths.SetPath(index, filename);
472 ASSERT(m_nBufferType[index] == BUFFERTYPE::NORMAL); // should have been initialized to BUFFERTYPE::NORMAL in constructor
473 if (!strDesc.empty())
475 m_strDesc[index] = strDesc;
476 m_nBufferType[index] = BUFFERTYPE::NORMAL_NAMED;
481 m_nBufferType[index] = BUFFERTYPE::UNNAMED;
482 m_strDesc[index] = strDesc;
484 UpdateHeaderPath(index);
485 m_pView[index]->ResizeWindow();
490 * @brief Load files and initialize frame's compare result icon
492 bool CHexMergeDoc::OpenDocs(int nFiles, const FileLocation fileloc[], const bool bRO[], const String strDesc[])
494 CHexMergeFrame *pf = GetParentFrame();
495 ASSERT(pf != nullptr);
496 bool bSucceeded = true;
497 int nNormalBuffer = 0;
499 for (nBuffer = 0; nBuffer < nFiles; nBuffer++)
501 if (FAILED(LoadOneFile(nBuffer, fileloc[nBuffer].filepath.c_str(), bRO[nBuffer], strDesc ? strDesc[nBuffer] : _T(""))))
506 if (m_nBufferType[nBuffer] == BUFFERTYPE::NORMAL || m_nBufferType[nBuffer] == BUFFERTYPE::NORMAL_NAMED)
509 if (nBuffer == nFiles)
511 // An extra ResizeWindow() on the left view aligns scroll ranges, and
512 // also triggers initial diff coloring by invalidating the client area.
513 m_pView[0]->ResizeWindow();
515 if (nNormalBuffer > 0)
518 UpdateDiffItem(m_pDirDoc);
522 // Use verify macro to trap possible error in debug.
523 VERIFY(pf->DestroyWindow());
528 void CHexMergeDoc::MoveOnLoad(int nPane, int)
532 nPane = GetOptionsMgr()->GetInt(OPT_ACTIVE_PANE);
533 if (nPane < 0 || nPane >= m_nBuffers)
537 GetParentFrame()->SetActivePane(nPane);
539 if (GetOptionsMgr()->GetBool(OPT_SCROLL_TO_FIRST))
540 m_pView[0]->SendMessage(WM_COMMAND, ID_FIRSTDIFF);
543 void CHexMergeDoc::CheckFileChanged(void)
545 for (int pane = 0; pane < m_nBuffers; ++pane)
547 if (m_pView[pane]->IsFileChangedOnDisk(m_filePaths[pane].c_str()) == FileChange::Changed)
549 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]);
550 if (AfxMessageBox(msg.c_str(), MB_YESNO | MB_ICONWARNING) == IDYES)
560 * @brief Write path and filename to headerbar
561 * @note SetText() does not repaint unchanged text
563 void CHexMergeDoc::UpdateHeaderPath(int pane)
565 CHexMergeFrame *pf = GetParentFrame();
566 ASSERT(pf != nullptr);
569 if (m_nBufferType[pane] == BUFFERTYPE::UNNAMED ||
570 m_nBufferType[pane] == BUFFERTYPE::NORMAL_NAMED)
572 sText = m_strDesc[pane];
576 sText = m_filePaths.GetPath(pane);
577 if (m_pDirDoc != nullptr)
578 m_pDirDoc->ApplyDisplayRoot(pane, sText);
580 if (m_pView[pane]->GetModified())
581 sText.insert(0, _T("* "));
582 pf->GetHeaderInterface()->SetText(pane, sText);
589 * @brief Customize a heksedit control's settings
591 static void Customize(IHexEditorWindow::Settings *settings)
593 settings->bSaveIni = false;
594 //settings->iAutomaticBPL = false;
595 //settings->iBytesPerLine = 16;
596 //settings->iFontSize = 8;
600 * @brief Customize a heksedit control's colors
602 static void Customize(IHexEditorWindow::Colors *colors)
604 COptionsMgr *pOptionsMgr = GetOptionsMgr();
605 colors->iSelBkColorValue = RGB(224, 224, 224);
606 colors->iDiffBkColorValue = pOptionsMgr->GetInt(OPT_CLR_DIFF);
607 colors->iSelDiffBkColorValue = pOptionsMgr->GetInt(OPT_CLR_SELECTED_DIFF);
608 colors->iDiffTextColorValue = pOptionsMgr->GetInt(OPT_CLR_DIFF_TEXT);
609 if (colors->iDiffTextColorValue == 0xFFFFFFFF)
610 colors->iDiffTextColorValue = 0;
611 colors->iSelDiffTextColorValue = pOptionsMgr->GetInt(OPT_CLR_SELECTED_DIFF_TEXT);
612 if (colors->iSelDiffTextColorValue == 0xFFFFFFFF)
613 colors->iSelDiffTextColorValue = 0;
614 SyntaxColors *pSyntaxColors = theApp.GetMainSyntaxColors();
615 colors->iTextColorValue = pSyntaxColors->GetColor(COLORINDEX_NORMALTEXT);
616 colors->iBkColorValue = pSyntaxColors->GetColor(COLORINDEX_BKGND);
617 colors->iSelTextColorValue = pSyntaxColors->GetColor(COLORINDEX_SELTEXT);
618 colors->iSelBkColorValue = pSyntaxColors->GetColor(COLORINDEX_SELBKGND);
622 * @brief Customize a heksedit control's settings and colors
624 static void Customize(IHexEditorWindow *pif)
626 Customize(pif->get_settings());
627 Customize(pif->get_colors());
628 //LANGID wLangID = (LANGID)GetThreadLocale();
629 //pif->load_lang(wLangID);
632 void CHexMergeDoc::RefreshOptions()
634 for (int nBuffer = 0; nBuffer < m_nBuffers; nBuffer++)
636 IHexEditorWindow *pif = m_pView[nBuffer]->GetInterface();
637 pif->read_ini_data();
639 pif->resize_window();
644 * @brief Update document filenames to title
646 void CHexMergeDoc::SetTitle(LPCTSTR lpszTitle)
648 String sTitle = (lpszTitle != nullptr) ? lpszTitle : CMergeFrameCommon::GetTitleString(m_filePaths, m_strDesc, &m_infoUnpacker, nullptr);
649 CDocument::SetTitle(sTitle.c_str());
653 * @brief We have two child views (left & right), so we keep pointers directly
654 * at them (the MFC view list doesn't have them both)
656 void CHexMergeDoc::SetMergeViews(CHexMergeView *pView[])
658 for (int nBuffer = 0; nBuffer < m_nBuffers; nBuffer++)
660 ASSERT(pView[nBuffer] != nullptr && m_pView[nBuffer] == nullptr);
661 m_pView[nBuffer] = pView[nBuffer];
662 m_pView[nBuffer]->m_nThisPane = nBuffer;
667 * @brief Called when "Save left" item is updated
669 void CHexMergeDoc::OnUpdateFileSaveLeft(CCmdUI* pCmdUI)
671 pCmdUI->Enable(m_pView[0]->GetModified());
675 * @brief Called when "Save middle" item is updated
677 void CHexMergeDoc::OnUpdateFileSaveMiddle(CCmdUI* pCmdUI)
679 pCmdUI->Enable(m_nBuffers == 3 && m_pView[1]->GetModified());
683 * @brief Called when "Save right" item is updated
685 void CHexMergeDoc::OnUpdateFileSaveRight(CCmdUI* pCmdUI)
687 pCmdUI->Enable(m_pView[m_nBuffers - 1]->GetModified());
691 * @brief Called when "Save" item is updated
693 void CHexMergeDoc::OnUpdateFileSave(CCmdUI* pCmdUI)
695 bool bModified = false;
696 for (int nBuffer = 0; nBuffer < m_nBuffers; nBuffer++)
697 bModified |= m_pView[nBuffer]->GetModified();
698 pCmdUI->Enable(bModified);
702 * @brief Reloads the opened files
704 void CHexMergeDoc::OnFileReload()
706 if (!PromptAndSaveIfNeeded(true))
709 FileLocation fileloc[3];
711 for (int pane = 0; pane < m_nBuffers; pane++)
713 fileloc[pane].setPath(m_filePaths[pane]);
714 bRO[pane] = m_pView[pane]->GetReadOnly();
716 if (!OpenDocs(m_nBuffers, fileloc, bRO, m_strDesc))
718 MoveOnLoad(GetActiveMergeView()->m_nThisPane);
722 * @brief Copy selected bytes from left to right
724 void CHexMergeDoc::OnL2r()
726 int dstPane = (GetActiveMergeView()->m_nThisPane < m_nBuffers - 1) ? GetActiveMergeView()->m_nThisPane + 1 : m_nBuffers - 1;
727 int srcPane = dstPane - 1;
728 CHexMergeView::CopySel(m_pView[srcPane], m_pView[dstPane]);
732 * @brief Copy selected bytes from right to left
734 void CHexMergeDoc::OnR2l()
736 int dstPane = (GetActiveMergeView()->m_nThisPane > 0) ? GetActiveMergeView()->m_nThisPane - 1 : 0;
737 int srcPane = dstPane + 1;
738 CHexMergeView::CopySel(m_pView[srcPane], m_pView[dstPane]);
742 * @brief Copy selected bytes from left to active pane
744 void CHexMergeDoc::OnCopyFromLeft()
746 int dstPane = GetActiveMergeView()->m_nThisPane;
747 int srcPane = (dstPane - 1 < 0) ? 0 : dstPane - 1;
748 CHexMergeView::CopySel(m_pView[srcPane], m_pView[dstPane]);
752 * @brief Copy selected bytes from right to active pane
754 void CHexMergeDoc::OnCopyFromRight()
756 int dstPane = GetActiveMergeView()->m_nThisPane;
757 int srcPane = (dstPane + 1 > m_nBuffers - 1) ? m_nBuffers - 1 : dstPane + 1;
758 CHexMergeView::CopySel(m_pView[srcPane], m_pView[dstPane]);
762 * @brief Copy all bytes from left to right
764 void CHexMergeDoc::OnAllRight()
766 int dstPane = (GetActiveMergeView()->m_nThisPane < m_nBuffers - 1) ? GetActiveMergeView()->m_nThisPane + 1 : m_nBuffers - 1;
767 int srcPane = dstPane - 1;
768 CHexMergeView::CopyAll(m_pView[srcPane], m_pView[dstPane]);
772 * @brief Copy all bytes from right to left
774 void CHexMergeDoc::OnAllLeft()
776 int dstPane = (GetActiveMergeView()->m_nThisPane > 0) ? GetActiveMergeView()->m_nThisPane - 1 : 0;
777 int srcPane = dstPane + 1;
778 CHexMergeView::CopyAll(m_pView[srcPane], m_pView[dstPane]);
782 * @brief Called when user selects View/Zoom In from menu.
784 void CHexMergeDoc::OnViewZoomIn()
786 for (int pane = 0; pane < m_nBuffers; pane++)
787 m_pView[pane]->ZoomText(1);
791 * @brief Called when user selects View/Zoom Out from menu.
793 void CHexMergeDoc::OnViewZoomOut()
795 for (int pane = 0; pane < m_nBuffers; pane++)
796 m_pView[pane]->ZoomText(-1);
800 * @brief Called when user selects View/Zoom Normal from menu.
802 void CHexMergeDoc::OnViewZoomNormal()
804 for (int pane = 0; pane < m_nBuffers; pane++)
805 m_pView[pane]->ZoomText(0);
808 void CHexMergeDoc::OnRefresh()
810 if (UpdateDiffItem(m_pDirDoc) == 0)
812 CMergeFrameCommon::ShowIdenticalMessage(m_filePaths, true,
813 [](LPCTSTR msg, UINT flags, UINT id) -> int { return AfxMessageBox(msg, flags, id); });
817 void CHexMergeDoc::OnFileRecompareAs(UINT nID)
819 FileLocation fileloc[3];
822 int nBuffers = m_nBuffers;
823 CDirDoc *pDirDoc = m_pDirDoc->GetMainView() ? m_pDirDoc :
824 static_cast<CDirDoc*>(theApp.m_pDirTemplate->CreateNewDocument());
825 PackingInfo infoUnpacker(m_infoUnpacker.GetPluginPipeline());
827 for (int nBuffer = 0; nBuffer < nBuffers; ++nBuffer)
829 fileloc[nBuffer].setPath(m_filePaths[nBuffer]);
830 dwFlags[nBuffer] = m_pView[nBuffer]->GetReadOnly() ? FFILEOPEN_READONLY : 0;
831 strDesc[nBuffer] = m_strDesc[nBuffer];
833 if (ID_UNPACKERS_FIRST <= nID && nID <= ID_UNPACKERS_LAST)
835 infoUnpacker.SetPluginPipeline(CMainFrame::GetPluginPipelineByMenuId(nID, FileTransform::UnpackerEventNames, ID_UNPACKERS_FIRST));
836 nID = ID_MERGE_COMPARE_HEX;
840 GetMainFrame()->ShowMergeDoc(nID, pDirDoc, nBuffers, fileloc, dwFlags, strDesc, _T(""), &infoUnpacker);
843 void CHexMergeDoc::OnOpenWithUnpacker()
845 CSelectPluginDlg dlg(m_infoUnpacker.GetPluginPipeline(),
846 strutils::join(m_filePaths.begin(), m_filePaths.end(), _T("|")), false, true);
847 if (dlg.DoModal() == IDOK)
849 PackingInfo infoUnpacker(dlg.GetPluginPipeline());
850 PathContext paths = m_filePaths;
851 DWORD dwFlags[3] = { FFILEOPEN_NOMRU, FFILEOPEN_NOMRU, FFILEOPEN_NOMRU };
852 String strDesc[3] = { m_strDesc[0], m_strDesc[1], m_strDesc[2] };
854 GetMainFrame()->DoFileOpen(ID_MERGE_COMPARE_HEX, &paths, dwFlags, strDesc, _T(""), &infoUnpacker);
858 void CHexMergeDoc::OnUpdateFileRecompareAs(CCmdUI* pCmdUI)
860 pCmdUI->Enable(pCmdUI->m_nID != ID_MERGE_COMPARE_HEX);