2 * @file WebPageDiffFrm.cpp
4 * @brief Implementation file for CWebPageDiffFrame
9 #include "WebPageDiffFrm.h"
14 #include "OptionsDef.h"
15 #include "OptionsMgr.h"
16 #include "OptionsDiffColors.h"
17 #include "OptionsDiffOptions.h"
18 #include "CompareOptions.h"
20 #include "PathContext.h"
22 #include "FileOrFolderSelect.h"
23 #include "SelectPluginDlg.h"
24 #include "FileLocation.h"
25 #include "Constants.h"
26 #include "Environment.h"
27 #include <Poco/RegularExpression.h>
34 #define BCN_DROPDOWN (BCN_FIRST + 0x0002)
37 template <typename T, typename Func>
38 struct CallbackImpl : public T
40 CallbackImpl(Func&& callback) : m_callback(std::move(callback)) {}
41 HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject) override { return E_NOTIMPL; }
42 ULONG STDMETHODCALLTYPE AddRef(void) override { return ++m_nRef; }
43 ULONG STDMETHODCALLTYPE Release(void) override { if (--m_nRef == 0) { delete this; return 0; } return m_nRef; }
44 HRESULT STDMETHODCALLTYPE Invoke(const WebDiffCallbackResult& result) { return m_callback(result); }
45 HRESULT STDMETHODCALLTYPE Invoke(const WebDiffEvent& event) { return m_callback(event); }
50 template<typename T, typename Func>
51 CComPtr<T> Callback(Func&& callback)
53 return CComPtr<T>(new CallbackImpl<T, Func>(std::move(callback)));
56 /////////////////////////////////////////////////////////////////////////////
59 IMPLEMENT_DYNCREATE(CWebPageDiffFrame, CMergeFrameCommon)
61 BEGIN_MESSAGE_MAP(CWebPageDiffFrame, CMergeFrameCommon)
62 //{{AFX_MSG_MAP(CWebPageDiffFrame)
69 ON_MESSAGE_VOID(WM_IDLEUPDATECMDUI, OnIdleUpdateCmdUI)
70 ON_MESSAGE(MSG_STORE_PANESIZES, OnStorePaneSizes)
72 ON_COMMAND(ID_FILE_CLOSE, OnFileClose)
73 ON_COMMAND(ID_RESCAN, OnFileReload)
74 ON_COMMAND_RANGE(ID_MERGE_COMPARE_TEXT, ID_MERGE_COMPARE_WEBPAGE, OnFileRecompareAs)
75 ON_UPDATE_COMMAND_UI_RANGE(ID_MERGE_COMPARE_TEXT, ID_MERGE_COMPARE_WEBPAGE, OnUpdateFileRecompareAs)
77 ON_COMMAND(ID_EDIT_CUT, OnEditCut)
78 ON_COMMAND(ID_EDIT_COPY, OnEditCopy)
79 ON_COMMAND(ID_EDIT_PASTE, OnEditPaste)
80 ON_COMMAND(ID_EDIT_UNDO, OnEditUndo)
81 ON_COMMAND(ID_EDIT_REDO, OnEditRedo)
82 ON_UPDATE_COMMAND_UI(ID_EDIT_UNDO, OnUpdateEditUndo)
83 ON_UPDATE_COMMAND_UI(ID_EDIT_REDO, OnUpdateEditRedo)
84 ON_COMMAND(ID_EDIT_SELECT_ALL, OnEditSelectAll)
86 ON_UPDATE_COMMAND_UI(ID_VIEW_LOCATION_BAR, OnUpdateControlBarMenu)
87 ON_COMMAND_EX(ID_VIEW_LOCATION_BAR, OnBarCheck)
88 ON_COMMAND(ID_VIEW_ZOOMIN, OnViewZoomIn)
89 ON_COMMAND(ID_VIEW_ZOOMOUT, OnViewZoomOut)
90 ON_COMMAND(ID_VIEW_ZOOMNORMAL, OnViewZoomNormal)
91 ON_COMMAND(ID_VIEW_LINEDIFFS, OnViewLineDiffs)
92 ON_UPDATE_COMMAND_UI(ID_VIEW_LINEDIFFS, OnUpdateViewLineDiffs)
93 ON_COMMAND(ID_VIEW_SPLITVERTICALLY, OnViewSplitVertically)
94 ON_UPDATE_COMMAND_UI(ID_VIEW_SPLITVERTICALLY, OnUpdateViewSplitVertically)
95 ON_COMMAND(ID_REFRESH, OnRefresh)
97 ON_COMMAND(ID_FIRSTDIFF, OnFirstdiff)
98 ON_UPDATE_COMMAND_UI(ID_FIRSTDIFF, OnUpdateFirstdiff)
99 ON_COMMAND(ID_LASTDIFF, OnLastdiff)
100 ON_UPDATE_COMMAND_UI(ID_LASTDIFF, OnUpdateLastdiff)
101 ON_COMMAND(ID_NEXTDIFF, OnNextdiff)
102 ON_UPDATE_COMMAND_UI(ID_NEXTDIFF, OnUpdateNextdiff)
103 ON_COMMAND(ID_PREVDIFF, OnPrevdiff)
104 ON_UPDATE_COMMAND_UI(ID_PREVDIFF, OnUpdatePrevdiff)
105 ON_COMMAND(ID_NEXTCONFLICT, OnNextConflict)
106 ON_UPDATE_COMMAND_UI(ID_NEXTCONFLICT, OnUpdateNextConflict)
107 ON_COMMAND(ID_PREVCONFLICT, OnPrevConflict)
108 ON_UPDATE_COMMAND_UI(ID_PREVCONFLICT, OnUpdatePrevConflict)
110 ON_COMMAND(ID_WEB_SIZE_FIT_TO_WINDOW, OnWebFitToWindow)
111 ON_UPDATE_COMMAND_UI(ID_WEB_SIZE_FIT_TO_WINDOW, OnUpdateWebFitToWindow)
112 ON_COMMAND_RANGE(ID_WEB_SIZE_320x512, ID_WEB_SIZE_1440x900, OnWebSize)
113 ON_COMMAND_RANGE(ID_WEB_COMPARE_SCREENSHOTS, ID_WEB_COMPARE_FULLSIZE_SCREENSHOTS, OnWebCompareScreenshots)
114 ON_COMMAND(ID_WEB_COMPARE_HTMLS, OnWebCompareHTMLs)
115 ON_COMMAND(ID_WEB_COMPARE_TEXTS, OnWebCompareTexts)
116 ON_COMMAND(ID_WEB_COMPARE_RESOURCETREES, OnWebCompareResourceTrees)
117 ON_COMMAND_RANGE(ID_WEB_CLEAR_DISK_CACHE, ID_WEB_CLEAR_ALL_PROFILE, OnWebClear)
119 // ON_COMMAND(ID_TOOLS_GENERATEREPORT, OnToolsGenerateReport)
121 ON_COMMAND_RANGE(ID_UNPACKERS_FIRST, ID_UNPACKERS_LAST, OnFileRecompareAs)
122 ON_COMMAND(ID_OPEN_WITH_UNPACKER, OnOpenWithUnpacker)
124 ON_COMMAND_RANGE(ID_NEXT_PANE, ID_PREV_PANE, OnWindowChangePane)
126 ON_COMMAND(ID_HELP, OnHelp)
128 ON_BN_CLICKED(IDC_FITTOWINDOW, OnBnClickedFitToWindow)
129 ON_BN_CLICKED(IDC_SHOWDIFFERENCES, OnBnClickedShowDifferences)
130 ON_BN_CLICKED(IDC_COMPARE, OnBnClickedCompare)
131 ON_EN_CHANGE(IDC_WIDTH, OnEnChangeWidth)
132 ON_EN_CHANGE(IDC_HEIGHT, OnEnChangeHeight)
133 ON_EN_CHANGE(IDC_ZOOM, OnEnChangeZoom)
134 ON_EN_CHANGE(IDC_USERAGENT, OnEnChangeUserAgent)
135 ON_EN_KILLFOCUS(IDC_WIDTH, OnKillFocusBarControls)
136 ON_EN_KILLFOCUS(IDC_HEIGHT, OnKillFocusBarControls)
137 ON_EN_KILLFOCUS(IDC_ZOOM, OnKillFocusBarControls)
138 ON_EN_KILLFOCUS(IDC_USERAGENT, OnKillFocusBarControls)
139 ON_NOTIFY(BCN_DROPDOWN, IDC_COMPARE, OnDropDownCompare)
141 ON_UPDATE_COMMAND_UI(ID_STATUS_DIFFNUM, OnUpdateStatusNum)
145 CMenu CWebPageDiffFrame::menu;
147 /////////////////////////////////////////////////////////////////////////////
148 // CWebPageDiffFrame construction/destruction
150 CWebPageDiffFrame::CWebPageDiffFrame()
151 : CMergeFrameCommon(IDI_EQUALWEBPAGE, IDI_NOTEQUALWEBPAGE)
153 , m_bAutoMerged(false)
154 , m_pWebDiffWindow(nullptr)
155 //, m_pWebToolWindow(nullptr)
156 , m_nBufferType{BUFFERTYPE::NORMAL, BUFFERTYPE::NORMAL, BUFFERTYPE::NORMAL}
159 , m_bInUpdateWebPageDiffBar(false)
160 , m_bCompareCompleted(false)
164 CWebPageDiffFrame::~CWebPageDiffFrame()
166 GetMainFrame()->UnwatchDocuments(this);
168 if (m_pDirDoc != nullptr)
170 m_pDirDoc->MergeDocClosing(this);
174 HMODULE hModule = GetModuleHandleW(L"WinWebDiffLib.dll");
175 if (hModule != nullptr)
177 bool (*pfnWinWebDiff_DestroyWindow)(IWebDiffWindow *) =
178 (bool (*)(IWebDiffWindow *))GetProcAddress(hModule, "WinWebDiff_DestroyWindow");
179 // bool (*pfnWinWebDiff_DestroyToolWindow)(IWebToolWindow *) =
180 // (bool (*)(IWebToolWindow *))GetProcAddress(hModule, "WinWebDiff_DestroyToolWindow");
181 if (pfnWinWebDiff_DestroyWindow != nullptr/* && pfnWinWebDiff_DestroyToolWindow != nullptr*/)
183 if (m_pWebDiffWindow != nullptr)
184 pfnWinWebDiff_DestroyWindow(m_pWebDiffWindow);
185 // if (m_pWebToolWindow != nullptr)
186 // pfnWinWebDiff_DestroyToolWindow(m_pWebToolWindow);
187 m_pWebDiffWindow = nullptr;
188 // m_pWebToolWindow = nullptr;
193 bool CWebPageDiffFrame::OpenDocs(int nFiles, const FileLocation fileloc[], const bool bRO[], const String strDesc[], CMDIFrameWnd *pParent, std::function<void ()> callback)
195 m_callbackOnOpenCompleted = callback;
196 m_bCompareCompleted = false;
198 CWaitCursor waitstatus;
199 int nNormalBuffer = 0;
200 for (int pane = 0; pane < nFiles; ++pane)
202 m_filePaths.SetPath(pane, fileloc[pane].filepath, false);
203 m_bRO[pane] = bRO[pane];
204 m_strDesc[pane] = strDesc ? strDesc[pane] : _T("");
205 if (fileloc[pane].filepath.empty())
206 m_nBufferType[pane] = BUFFERTYPE::UNNAMED;
209 m_nBufferType[pane] = (!strDesc || strDesc[pane].empty()) ? BUFFERTYPE::NORMAL : BUFFERTYPE::NORMAL_NAMED;
215 LPCTSTR lpszWndClass = AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW,
216 ::LoadCursor(nullptr, IDC_ARROW), (HBRUSH)(COLOR_WINDOW+1), nullptr);
218 if (!CMergeFrameCommon::Create(lpszWndClass, GetTitle(), WS_OVERLAPPEDWINDOW | WS_CHILD, rectDefault, pParent))
221 int nCmdShow = SW_SHOW;
222 if (GetOptionsMgr()->GetBool(OPT_ACTIVE_FRAME_MAX))
223 nCmdShow = SW_SHOWMAXIMIZED;
224 ShowWindow(nCmdShow);
225 BringToTop(nCmdShow);
227 GetParent()->ModifyStyleEx(WS_EX_CLIENTEDGE, 0, SWP_DRAWFRAME);
229 GetMainFrame()->WatchDocuments(this);
234 void CWebPageDiffFrame::MoveOnLoad(int nPane, int)
238 nPane = (m_nBufferType[0] != BUFFERTYPE::UNNAMED) ? GetOptionsMgr()->GetInt(OPT_ACTIVE_PANE) : 0;
239 if (nPane < 0 || nPane >= m_pWebDiffWindow->GetPaneCount())
243 m_pWebDiffWindow->SetActivePane(nPane);
245 if (GetOptionsMgr()->GetBool(OPT_SCROLL_TO_FIRST) && m_pWebDiffWindow->GetDiffCount() > 0)
246 m_pWebDiffWindow->SelectDiff(0);
250 * @brief DirDoc gives us its identity just after it creates us
252 void CWebPageDiffFrame::SetDirDoc(CDirDoc * pDirDoc)
254 ASSERT(pDirDoc != nullptr && m_pDirDoc == nullptr);
258 IMergeDoc::FileChange CWebPageDiffFrame::IsFileChangedOnDisk(int pane) const
261 if (!dfi.Update(m_filePaths[pane]))
262 return FileChange::Removed;
264 if (GetOptionsMgr()->GetBool(OPT_IGNORE_SMALL_FILETIME))
265 tolerance = SmallTimeDiff; // From MainFrm.h
266 int64_t timeDiff = dfi.mtime - m_fileInfo[pane].mtime;
267 if (timeDiff < 0) timeDiff = -timeDiff;
268 if ((timeDiff > tolerance * Poco::Timestamp::resolution()) || (dfi.size != m_fileInfo[pane].size))
269 return FileChange::Changed;
270 return FileChange::NoChange;
273 void CWebPageDiffFrame::CheckFileChanged(void)
275 for (int pane = 0; pane < m_pWebDiffWindow->GetPaneCount(); ++pane)
277 if (IsFileChangedOnDisk(pane) == FileChange::Changed)
279 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]);
280 if (AfxMessageBox(msg.c_str(), MB_YESNO | MB_ICONWARNING | MB_DONT_ASK_AGAIN, IDS_FILECHANGED_RESCAN) == IDYES)
290 * @brief Create a status bar to be associated with a heksedit control
292 void CWebPageDiffFrame::CreateWebWndStatusBar(CStatusBar &wndStatusBar, CWnd *pwndPane)
294 wndStatusBar.Create(pwndPane, WS_CHILD|WS_VISIBLE);
295 wndStatusBar.SetIndicators(0, 1);
296 wndStatusBar.SetPaneInfo(0, 0, SBPS_STRETCH, 0);
297 wndStatusBar.SetParent(this);
298 wndStatusBar.SetWindowPos(&wndBottom, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
301 static bool isTempFile(const String& path)
303 String tmpDir = env::GetTemporaryPath();
304 strutils::replace(tmpDir, _T("\\"), _T("/"));
305 tmpDir = _T("file:///") + tmpDir;
306 return (path.find(tmpDir) == 0);
309 void CWebPageDiffFrame::OnWebDiffEvent(const WebDiffEvent& event)
313 case WebDiffEvent::SourceChanged:
314 case WebDiffEvent::TabChanged:
316 if (m_nBufferType[event.pane] == BUFFERTYPE::UNNAMED)
318 m_nBufferType[event.pane] = BUFFERTYPE::NORMAL;
319 m_strDesc[event.pane].clear();
321 String curUrl = m_pWebDiffWindow->GetCurrentUrl(event.pane);
322 if (!isTempFile(curUrl) && curUrl != _T("about:blank"))
324 m_filePaths[event.pane] = paths::isFileURL(curUrl) ? paths::FromURL(curUrl) : curUrl;
325 UpdateHeaderPath(event.pane);
329 case WebDiffEvent::ZoomFactorChanged:
330 UpdateWebPageDiffBar();
336 * @brief returns true if WinWebDiffLib.dll is loadable
338 bool CWebPageDiffFrame::IsLoadable()
340 static HMODULE hModule;
341 if (hModule == nullptr)
343 hModule = LoadLibraryW(L"WinWebDiff\\WinWebDiffLib.dll");
344 if (hModule == nullptr)
352 * @brief returns true if URL matches configured pattern
354 bool CWebPageDiffFrame::MatchURLPattern(const String& url)
356 const String& includePattern = GetOptionsMgr()->GetString(OPT_CMP_WEB_URL_PATTERN_TO_INCLUDE);
357 if (includePattern.empty())
359 std::string textu8 = ucr::toUTF8(url);
362 Poco::RegularExpression reInclude(ucr::toUTF8(includePattern));
363 if (!reInclude.match(textu8))
365 const String& excludePattern = GetOptionsMgr()->GetString(OPT_CMP_WEB_URL_PATTERN_TO_EXCLUDE);
366 if (excludePattern.empty())
368 Poco::RegularExpression reExclude(ucr::toUTF8(excludePattern));
369 return !reExclude.match(textu8);
378 * @brief Create the splitter, the filename bar, the status bar, and the two views
380 BOOL CWebPageDiffFrame::OnCreateClient(LPCREATESTRUCT /*lpcs*/,
381 CCreateContext* pContext)
386 HMODULE hModule = GetModuleHandleW(L"WinWebDiffLib.dll");
387 if (hModule == nullptr)
390 IWebDiffWindow * (*pfnWinWebDiff_CreateWindow)(HINSTANCE hInstance, HWND hWndParent, int nID) =
391 (IWebDiffWindow * (*)(HINSTANCE hInstance, HWND hWndParent, int nID))GetProcAddress(hModule, "WinWebDiff_CreateWindow");
392 if (pfnWinWebDiff_CreateWindow == nullptr ||
393 (m_pWebDiffWindow = pfnWinWebDiff_CreateWindow(hModule, m_hWnd, AFX_IDW_PANE_FIRST)) == nullptr)
395 FreeLibrary(hModule);
399 if (!m_pWebDiffWindow->IsWebView2Installed())
401 if (IDYES == AfxMessageBox(_("WebView2 runtime is not installed. Do you want to download it?").c_str(), MB_ICONWARNING | MB_YESNO))
403 m_pWebDiffWindow->DownloadWebView2();
408 m_pWebDiffWindow->AddEventListener(
409 Callback<IWebDiffEventHandler>([this](const WebDiffEvent& event) -> HRESULT
411 OnWebDiffEvent(event);
418 m_pWebDiffWindow->SetUserDataFolderType(
419 static_cast<IWebDiffWindow::UserdataFolderType>(GetOptionsMgr()->GetInt(OPT_CMP_WEB_USERDATAFOLDER_TYPE)),
420 GetOptionsMgr()->GetBool(OPT_CMP_WEB_USERDATAFOLDER_PERPANE));
422 auto callback = Callback<IWebDiffCallback>([this](const WebDiffCallbackResult& result) -> HRESULT
424 int nNormalBuffer = 0;
425 for (int pane = 0; pane < m_pWebDiffWindow->GetPaneCount(); ++pane)
427 if (m_nBufferType[pane] != BUFFERTYPE::UNNAMED)
430 if (nNormalBuffer == 0)
431 UpdateDiffItem(m_pDirDoc);
433 if (GetOptionsMgr()->GetBool(OPT_SCROLL_TO_FIRST))
434 m_pWebDiffWindow->FirstDiff();
436 if (m_callbackOnOpenCompleted)
438 m_callbackOnOpenCompleted();
439 m_callbackOnOpenCompleted = nullptr;
441 m_bCompareCompleted = true;
445 if (std::count(m_nBufferType, m_nBufferType + m_filePaths.GetSize(), BUFFERTYPE::UNNAMED) == m_filePaths.GetSize())
447 for (int pane = 0; pane < m_filePaths.GetSize(); ++pane)
448 m_filePaths[pane] = _T("about:blank");
450 bResult = OpenUrls(callback);
452 for (int pane = 0; pane < m_filePaths.GetSize(); ++pane)
454 m_fileInfo[pane].Update(m_filePaths[pane]);
457 // Merge frame has also a dockable bar at the very left
458 // This is not the client area, but we create it now because we want
459 // to use the CCreateContext
460 // String sCaption = theApp.LoadString(IDS_LOCBAR_CAPTION);
461 // if (!m_wndLocationBar.Create(this, sCaption.c_str(), WS_CHILD | WS_VISIBLE, ID_VIEW_LOCATION_BAR))
463 // TRACE0("Failed to create LocationBar\n");
467 // IWebToolWindow * (*pfnWinWebDiff_CreateToolWindow)(HINSTANCE hInstance, HWND hWndParent, IWebDiffWindow *) =
468 // (IWebToolWindow * (*)(HINSTANCE hInstance, HWND hWndParent, IWebDiffWindow *pWebPageDiffWindow))GetProcAddress(hModule, "WinWebDiff_CreateToolWindow");
469 // if (pfnWinWebDiff_CreateToolWindow == nullptr ||
470 // (m_pWebToolWindow = pfnWinWebDiff_CreateToolWindow(hModule, m_wndLocationBar.m_hWnd, m_pWebDiffWindow)) == nullptr)
475 // m_pWebToolWindow->Translate(TranslateLocationPane);
477 // m_wndLocationBar.SetFrameHwnd(GetSafeHwnd());
482 //void CWebPageDiffFrame::TranslateLocationPane(int id, const wchar_t *org, size_t dstbufsize, wchar_t *dst)
484 // swprintf_s(dst, dstbufsize, L"%s", tr("WebPageDiffFrame|LocationPane", ucr::toUTF8(org)).c_str());
487 /////////////////////////////////////////////////////////////////////////////
488 // CWebPageDiffFrame message handlers
490 int CWebPageDiffFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
492 if (CMergeFrameCommon::OnCreate(lpCreateStruct) == -1)
495 EnableDocking(CBRS_ALIGN_TOP | CBRS_ALIGN_BOTTOM | CBRS_ALIGN_LEFT | CBRS_ALIGN_RIGHT);
497 CMergeFrameCommon::RemoveBarBorder();
499 // Merge frame has a header bar at top
500 if (!m_wndWebPageDiffBar.Create(this) || !m_wndFilePathBar.Create(this))
502 TRACE0("Failed to create dialog bar\n");
503 return -1; // fail to create
506 UpdateWebPageDiffBar();
508 m_wndFilePathBar.SetPaneCount(m_pWebDiffWindow->GetPaneCount());
509 m_wndFilePathBar.SetOnSetFocusCallback([&](int pane) {
510 if (m_nActivePane != pane)
511 m_pWebDiffWindow->SetActivePane(pane);
513 m_wndFilePathBar.SetOnCaptionChangedCallback([&](int pane, const String& sText) {
514 m_strDesc[pane] = sText;
515 UpdateHeaderPath(pane);
518 // Merge frame also has a dockable bar at the very left
519 // created in OnCreateClient
520 //m_wndLocationBar.SetBarStyle(m_wndLocationBar.GetBarStyle() |
521 // CBRS_SIZE_DYNAMIC | CBRS_ALIGN_LEFT);
522 //m_wndLocationBar.EnableDocking(CBRS_ALIGN_LEFT | CBRS_ALIGN_RIGHT);
523 //DockControlBar(&m_wndLocationBar, AFX_IDW_DOCKBAR_LEFT);
525 for (int nPane = 0; nPane < m_pWebDiffWindow->GetPaneCount(); nPane++)
527 m_wndFilePathBar.SetActive(nPane, FALSE);
528 // CreateWebWndStatusBar(m_wndStatusBar[nPane], CWnd::FromHandle(m_pWebDiffWindow->GetPaneHWND(nPane)));
529 UpdateHeaderPath(nPane);
532 // CSize size = m_wndStatusBar[0].CalcFixedLayout(TRUE, TRUE);
533 // m_rectBorder.bottom = size.cy;
535 CDockState pDockState;
536 pDockState.LoadState(_T("Settings-WebPageDiffFrame"));
537 if (EnsureValidDockState(pDockState)) // checks for valid so won't ASSERT
538 SetDockState(pDockState);
539 // for the dimensions of the diff and location pane, use the CSizingControlBar loader
540 //m_wndLocationBar.LoadState(_T("Settings-WebPageDiffFrame"));
546 * @brief We must use this function before a call to SetDockState
548 * @note Without this, SetDockState will assert or crash if a bar from the
549 * CDockState is missing in the current CMergeEditFrame.
550 * The bars are identified with their ID. This means the missing bar bug is triggered
551 * when we run WinMerge after changing the ID of a bar.
553 bool CWebPageDiffFrame::EnsureValidDockState(CDockState& state)
555 for (int i = (int)state.m_arrBarInfo.GetSize() - 1; i >= 0; i--)
557 bool barIsCorrect = true;
558 CControlBarInfo* pInfo = (CControlBarInfo*)state.m_arrBarInfo[i];
559 if (pInfo == nullptr)
560 barIsCorrect = false;
563 if (!pInfo->m_bFloating)
565 pInfo->m_pBar = GetControlBar(pInfo->m_nBarID);
566 if (pInfo->m_pBar == nullptr)
567 barIsCorrect = false; //toolbar id's probably changed
572 state.m_arrBarInfo.RemoveAt(i);
578 * @brief Save the window's position, free related resources, and destroy the window
580 BOOL CWebPageDiffFrame::DestroyWindow()
586 CFrameWnd* pParentFrame = GetParentFrame();
587 BOOL result = CMergeFrameCommon::DestroyWindow();
589 pParentFrame->OnUpdateFrameTitle(FALSE);
593 void CWebPageDiffFrame::LoadOptions()
595 m_pWebDiffWindow->SetHorizontalSplit(GetOptionsMgr()->GetBool(OPT_SPLIT_HORIZONTALLY));
596 m_pWebDiffWindow->SetZoom(GetOptionsMgr()->GetInt(OPT_CMP_WEB_ZOOM) / 1000.0);
597 SIZE size{ GetOptionsMgr()->GetInt(OPT_CMP_WEB_VIEW_WIDTH), GetOptionsMgr()->GetInt(OPT_CMP_WEB_VIEW_HEIGHT) };
598 m_pWebDiffWindow->SetSize(size);
599 m_pWebDiffWindow->SetFitToWindow(GetOptionsMgr()->GetBool(OPT_CMP_WEB_FIT_TO_WINDOW));
600 m_pWebDiffWindow->SetShowDifferences(GetOptionsMgr()->GetBool(OPT_CMP_WEB_SHOWDIFFERENCES));
601 m_pWebDiffWindow->SetShowWordDifferences(GetOptionsMgr()->GetBool(OPT_WORDDIFF_HIGHLIGHT));
602 m_pWebDiffWindow->SetUserAgent(GetOptionsMgr()->GetString(OPT_CMP_WEB_USER_AGENT).c_str());
603 COLORSETTINGS colors;
604 IWebDiffWindow::ColorSettings colorSettings;
605 Options::DiffColors::Load(GetOptionsMgr(), colors);
606 colorSettings.clrDiff = colors.clrDiff;
607 colorSettings.clrDiffText = colors.clrDiffText;
608 colorSettings.clrSelDiff = colors.clrSelDiff;
609 colorSettings.clrSelDiffText = colors.clrSelDiffText;
610 colorSettings.clrSNP = colors.clrSNP;
611 colorSettings.clrSNPText = colors.clrSNPText;
612 colorSettings.clrSelSNP = colors.clrSelSNP;
613 colorSettings.clrSelSNPText = colors.clrSelSNPText;
614 colorSettings.clrWordDiff = colors.clrWordDiff;
615 colorSettings.clrWordDiffDeleted = colors.clrWordDiffDeleted;
616 colorSettings.clrWordDiffText = colors.clrWordDiffText;
617 colorSettings.clrSelWordDiff = colors.clrSelWordDiff;
618 colorSettings.clrSelWordDiffDeleted = colors.clrSelWordDiffDeleted;
619 colorSettings.clrSelWordDiffText = colors.clrSelWordDiffText;
620 m_pWebDiffWindow->SetDiffColorSettings(colorSettings);
622 IWebDiffWindow::DiffOptions diffOptions;
623 Options::DiffOptions::Load(GetOptionsMgr(), options);
624 diffOptions.bFilterCommentsLines = options.bFilterCommentsLines;
625 diffOptions.completelyBlankOutIgnoredChanges = options.bCompletelyBlankOutIgnoredChanges;
626 diffOptions.diffAlgorithm = options.nDiffAlgorithm;
627 diffOptions.ignoreBlankLines = options.bIgnoreBlankLines;
628 diffOptions.ignoreCase = options.bIgnoreCase;
629 diffOptions.ignoreEol = options.bIgnoreEol;
630 diffOptions.ignoreNumbers = options.bIgnoreNumbers;
631 diffOptions.ignoreWhitespace = options.nIgnoreWhitespace;
632 m_pWebDiffWindow->SetDiffOptions(diffOptions);
635 void CWebPageDiffFrame::SaveOptions()
637 // GetOptionsMgr()->SaveOption(OPT_CMP_WEB_DIFFCOLORALPHA, static_cast<int>(m_pWebDiffWindow->GetDiffColorAlpha() * 100.0));
638 SIZE size = m_pWebDiffWindow->GetSize();
639 GetOptionsMgr()->SaveOption(OPT_CMP_WEB_VIEW_WIDTH, size.cx);
640 GetOptionsMgr()->SaveOption(OPT_CMP_WEB_VIEW_HEIGHT, size.cy);
641 GetOptionsMgr()->SaveOption(OPT_CMP_WEB_FIT_TO_WINDOW, m_pWebDiffWindow->GetFitToWindow());
642 GetOptionsMgr()->SaveOption(OPT_CMP_WEB_SHOWDIFFERENCES, m_pWebDiffWindow->GetShowDifferences());
643 GetOptionsMgr()->SaveOption(OPT_CMP_WEB_ZOOM, static_cast<int>(m_pWebDiffWindow->GetZoom() * 1000));
644 GetOptionsMgr()->SaveOption(OPT_CMP_WEB_USER_AGENT, m_pWebDiffWindow->GetUserAgent());
648 * @brief Save coordinates of the frame, splitters, and bars
650 * @note Do not save the maximized/restored state here. We are interested
651 * in the state of the active frame, and maybe this frame is not active
653 void CWebPageDiffFrame::SavePosition()
658 // save the bars layout
659 // save docking positions and sizes
660 CDockState m_pDockState;
661 GetDockState(m_pDockState);
662 m_pDockState.SaveState(_T("Settings-WebPageDiffFrame"));
663 // for the dimensions of the diff pane, use the CSizingControlBar save
664 //m_wndLocationBar.SaveState(_T("Settings-WebPageDiffFrame"));
667 void CWebPageDiffFrame::SaveActivePane()
669 GetOptionsMgr()->SaveOption(OPT_ACTIVE_PANE, m_pWebDiffWindow->GetActivePane());
672 void CWebPageDiffFrame::OnMDIActivate(BOOL bActivate, CWnd* pActivateWnd, CWnd* pDeactivateWnd)
674 CMergeFrameCommon::OnMDIActivate(bActivate, pActivateWnd, pDeactivateWnd);
678 GetMainFrame()->PostMessage(WM_USER + 1);
682 void CWebPageDiffFrame::OnClose()
684 // clean up pointers.
685 CMergeFrameCommon::OnClose();
688 void CWebPageDiffFrame::OnDestroy()
690 if (!m_pWebDiffWindow)
695 * @brief Reloads the opened files
697 void CWebPageDiffFrame::OnFileReload()
699 int nActivePane = m_pWebDiffWindow->GetActivePane();
701 Callback<IWebDiffCallback>([nActivePane, this](const WebDiffCallbackResult& result) -> HRESULT
703 MoveOnLoad(nActivePane);
704 for (int pane = 0; pane < m_filePaths.GetSize(); ++pane)
705 m_fileInfo[pane].Update(m_filePaths[pane]);
710 void CWebPageDiffFrame::OnFileClose()
715 void CWebPageDiffFrame::OnFileRecompareAs(UINT nID)
717 PathContext paths = m_filePaths;
720 int nBuffers = m_filePaths.GetSize();
721 PackingInfo infoUnpacker(m_infoUnpacker.GetPluginPipeline());
723 for (int nBuffer = 0; nBuffer < nBuffers; ++nBuffer)
725 dwFlags[nBuffer] = m_bRO[nBuffer] ? FFILEOPEN_READONLY : 0;
726 strDesc[nBuffer] = m_strDesc[nBuffer];
728 if (ID_UNPACKERS_FIRST <= nID && nID <= ID_UNPACKERS_LAST)
730 infoUnpacker.SetPluginPipeline(CMainFrame::GetPluginPipelineByMenuId(nID, FileTransform::UnpackerEventNames, ID_UNPACKERS_FIRST));
731 nID = GetOptionsMgr()->GetBool(OPT_PLUGINS_OPEN_IN_SAME_FRAME_TYPE) ? ID_MERGE_COMPARE_WEBPAGE : -ID_MERGE_COMPARE_WEBPAGE;
735 GetMainFrame()->DoFileOrFolderOpen(&paths, dwFlags, strDesc, _T(""),
736 GetOptionsMgr()->GetBool(OPT_CMP_INCLUDE_SUBDIRS), nullptr, &infoUnpacker, nullptr, nID);
739 void CWebPageDiffFrame::OnUpdateFileRecompareAs(CCmdUI* pCmdUI)
741 pCmdUI->Enable(pCmdUI->m_nID != ID_MERGE_COMPARE_WEBPAGE);
744 void CWebPageDiffFrame::OnOpenWithUnpacker()
746 CSelectPluginDlg dlg(m_infoUnpacker.GetPluginPipeline(),
747 strutils::join(m_filePaths.begin(), m_filePaths.end(), _T("|")),
748 CSelectPluginDlg::PluginType::Unpacker, false);
749 if (dlg.DoModal() == IDOK)
751 PackingInfo infoUnpacker(dlg.GetPluginPipeline());
752 PathContext paths = m_filePaths;
753 DWORD dwFlags[3] = { FFILEOPEN_NOMRU, FFILEOPEN_NOMRU, FFILEOPEN_NOMRU };
754 String strDesc[3] = { m_strDesc[0], m_strDesc[1], m_strDesc[2] };
756 GetMainFrame()->DoFileOpen(
757 GetOptionsMgr()->GetBool(OPT_PLUGINS_OPEN_IN_SAME_FRAME_TYPE) ? ID_MERGE_COMPARE_WEBPAGE: -1,
758 &paths, dwFlags, strDesc, _T(""), &infoUnpacker);
762 void CWebPageDiffFrame::OnWindowChangePane(UINT nID)
764 int npanes = m_pWebDiffWindow->GetPaneCount();
765 int pane = m_pWebDiffWindow->GetActivePane();
766 pane = (nID == ID_NEXT_PANE) ? ((pane + 1) % npanes) : ((pane + npanes - 1) % npanes);
767 m_pWebDiffWindow->SetActivePane(pane);
771 * @brief Write path and filename to headerbar
772 * @note SetText() does not repaint unchanged text
774 void CWebPageDiffFrame::UpdateHeaderPath(int pane)
778 if (m_nBufferType[pane] == BUFFERTYPE::UNNAMED ||
779 m_nBufferType[pane] == BUFFERTYPE::NORMAL_NAMED)
781 sText = m_strDesc[pane];
785 sText = m_filePaths.GetPath(pane);
786 if (m_pDirDoc != nullptr)
787 m_pDirDoc->ApplyDisplayRoot(pane, sText);
790 m_wndFilePathBar.SetText(pane, sText.c_str());
795 /// update splitting position for panels 1/2 and headerbar and statusbar
796 void CWebPageDiffFrame::UpdateHeaderSizes()
798 if (m_pWebDiffWindow != nullptr)
801 CRect rc, rcMergeWindow;
802 int nPaneCount = m_pWebDiffWindow->GetPaneCount();
804 ::GetWindowRect(m_pWebDiffWindow->GetHWND(), &rcMergeWindow);
805 ScreenToClient(rcMergeWindow);
806 if (!m_pWebDiffWindow->GetHorizontalSplit())
808 for (int pane = 0; pane < nPaneCount; pane++)
810 RECT rc1 = m_pWebDiffWindow->GetPaneWindowRect(pane);
811 w[pane] = rc1.right - rc1.left - 4;
812 if (w[pane]<1) w[pane]=1; // Perry 2003-01-22 (I don't know why this happens)
817 for (int pane = 0; pane < nPaneCount; pane++)
818 w[pane] = rcMergeWindow.Width() / nPaneCount - 4;
821 if (!std::equal(m_nLastSplitPos, m_nLastSplitPos + nPaneCount - 1, w))
823 std::copy_n(w, nPaneCount - 1, m_nLastSplitPos);
825 // resize controls in header dialog bar
826 m_wndFilePathBar.Resize(w);
828 rc.left = rcMergeWindow.left;
829 rc.top = rc.bottom - m_rectBorder.bottom;
831 for (int pane = 0; pane < nPaneCount; pane++)
833 rc.right += w[pane] + 4 + 2;
834 // m_wndStatusBar[pane].MoveWindow(&rc);
842 * @brief Update document filenames to title
844 void CWebPageDiffFrame::SetTitle(LPCTSTR lpszTitle)
846 String sTitle = (lpszTitle != nullptr) ? lpszTitle : CMergeFrameCommon::GetTitleString(m_filePaths, m_strDesc, &m_infoUnpacker, nullptr);
847 CMergeFrameCommon::SetTitle(sTitle.c_str());
848 if (m_hWnd != nullptr)
850 SetWindowText(sTitle.c_str());
851 GetMainFrame()->OnUpdateFrameTitle(TRUE);
855 void CWebPageDiffFrame::UpdateLastCompareResult()
857 if (m_bCompareCompleted)
858 SetLastCompareResult(m_pWebDiffWindow->GetDiffCount() > 0 ? 1 : 0);
861 void CWebPageDiffFrame::UpdateAutoPaneResize()
865 void CWebPageDiffFrame::UpdateSplitter()
869 bool CWebPageDiffFrame::OpenUrls(IWebDiffCallback* callback)
872 String filteredFilenames = strutils::join(m_filePaths.begin(), m_filePaths.end(), _T("|"));
873 String strTempFileName[3];
874 m_infoUnpacker.EnableWebBrowserMode();
875 for (int pane = 0; pane < m_filePaths.GetSize(); ++pane)
877 strTempFileName[pane] = m_filePaths[pane];
878 if (!m_infoUnpacker.Unpacking(&m_unpackerSubcodes[pane], strTempFileName[pane], filteredFilenames, {strTempFileName[pane]}))
883 if (m_filePaths.GetSize() == 2)
884 bResult = SUCCEEDED(m_pWebDiffWindow->Open(ucr::toUTF16(strTempFileName[0]).c_str(), ucr::toUTF16(strTempFileName[1]).c_str(), callback));
886 bResult = SUCCEEDED(m_pWebDiffWindow->Open(ucr::toUTF16(strTempFileName[0]).c_str(), ucr::toUTF16(strTempFileName[1]).c_str(), ucr::toUTF16(strTempFileName[2]).c_str(), callback));
891 * @brief Update associated diff item
893 int CWebPageDiffFrame::UpdateDiffItem(CDirDoc *pDirDoc)
895 // If directory compare has results
896 if (pDirDoc && pDirDoc->HasDiffs())
899 // const String &pathLeft = m_filePaths.GetLeft();
900 // const String &pathRight = m_filePaths.GetRight();
901 // CDiffContext &ctxt = const_cast<CDiffContext &>(pDirDoc->GetDiffContext());
902 // if (UINT_PTR pos = pDirDoc->FindItemFromPaths(pathLeft, pathRight))
904 // DIFFITEM &di = pDirDoc->GetDiffRefByKey(pos);
905 // ::UpdateDiffItem(m_nBuffers, di, &ctxt);
908 int result = m_pWebDiffWindow->GetDiffCount() > 0 ? 1 : 0;
909 SetLastCompareResult(result != 0);
913 /// Document commanding us to close
914 bool CWebPageDiffFrame::CloseNow()
921 * @brief A string to display as a tooltip for MDITabbar
923 CString CWebPageDiffFrame::GetTooltipString() const
925 return CMergeFrameCommon::GetTooltipString(m_filePaths, m_strDesc, &m_infoUnpacker, nullptr).c_str();
929 * @brief Update any resources necessary after a GUI language change
931 void CWebPageDiffFrame::UpdateResources()
933 //m_pWebToolWindow->Translate(TranslateLocationPane);
936 void CWebPageDiffFrame::RefreshOptions()
942 * @brief Handle some keys when in merging mode
944 bool CWebPageDiffFrame::MergeModeKeyDown(MSG* pMsg)
946 bool bHandled = false;
948 // Allow default text selection when SHIFT pressed
949 if (::GetAsyncKeyState(VK_SHIFT))
952 // Allow default editor functions when CTRL pressed
953 if (::GetAsyncKeyState(VK_CONTROL))
956 // If we are in merging mode (merge with cursor keys)
957 // handle some keys here
958 switch (pMsg->wParam)
973 * @brief Check for keyboard commands
975 BOOL CWebPageDiffFrame::PreTranslateMessage(MSG* pMsg)
977 if (pMsg->message == WM_KEYDOWN)
979 // If we are in merging mode (merge with cursor keys)
980 // handle some keys here
981 if (theApp.GetMergingMode())
983 bool bHandled = MergeModeKeyDown(pMsg);
988 // Close window in response to VK_ESCAPE if user has allowed it from options
989 if (pMsg->wParam == VK_ESCAPE && GetOptionsMgr()->GetInt(OPT_CLOSE_WITH_ESC) != 0)
991 PostMessage(WM_CLOSE, 0, 0);
995 return CMergeFrameCommon::PreTranslateMessage(pMsg);
998 void CWebPageDiffFrame::OnSize(UINT nType, int cx, int cy)
1000 CMergeFrameCommon::OnSize(nType, cx, cy);
1001 UpdateHeaderSizes();
1005 * @brief Synchronize control and status bar placements with splitter position,
1006 * update mod indicators, synchronize scrollbars
1008 void CWebPageDiffFrame::OnIdleUpdateCmdUI()
1010 if (IsWindowVisible())
1012 int nActivePane = m_pWebDiffWindow->GetActivePane();
1013 if (nActivePane != -1)
1014 m_nActivePane = nActivePane;
1016 UpdateHeaderSizes();
1017 for (int pane = 0; pane < m_filePaths.GetSize(); ++pane)
1019 // Update mod indicators
1020 m_wndFilePathBar.SetActive(pane, pane == nActivePane);
1022 UpdateLastCompareResult();
1024 CMergeFrameCommon::OnIdleUpdateCmdUI();
1028 * @brief Save pane sizes and positions when one of panes requests it.
1030 LRESULT CWebPageDiffFrame::OnStorePaneSizes(WPARAM wParam, LPARAM lParam)
1036 void CWebPageDiffFrame::UpdateWebPageDiffBar()
1038 m_bInUpdateWebPageDiffBar = true;
1039 bool fitToWindow = m_pWebDiffWindow->GetFitToWindow();
1040 m_wndWebPageDiffBar.CheckDlgButton(IDC_FITTOWINDOW, fitToWindow);
1041 m_wndWebPageDiffBar.CheckDlgButton(IDC_SHOWDIFFERENCES, m_pWebDiffWindow->GetShowDifferences());
1042 m_wndWebPageDiffBar.GetDlgItem(IDC_WIDTH)->EnableWindow(!fitToWindow);
1043 m_wndWebPageDiffBar.GetDlgItem(IDC_HEIGHT)->EnableWindow(!fitToWindow);
1044 SIZE size = m_pWebDiffWindow->GetSize();
1045 m_wndWebPageDiffBar.SetDlgItemText(IDC_WIDTH, strutils::format(_T("%d"), size.cx));
1046 m_wndWebPageDiffBar.SetDlgItemText(IDC_HEIGHT, strutils::format(_T("%d"), size.cy));
1047 m_wndWebPageDiffBar.SetDlgItemText(IDC_ZOOM, strutils::format(_T("%.1f%%"),
1048 m_pWebDiffWindow->GetZoom() * 100.0));
1049 m_wndWebPageDiffBar.SetDlgItemText(IDC_USERAGENT, m_pWebDiffWindow->GetUserAgent());
1050 m_bInUpdateWebPageDiffBar = false;
1053 void CWebPageDiffFrame::OnBnClickedFitToWindow()
1055 m_pWebDiffWindow->SetFitToWindow(m_wndWebPageDiffBar.IsDlgButtonChecked(IDC_FITTOWINDOW));
1056 UpdateWebPageDiffBar();
1059 void CWebPageDiffFrame::OnBnClickedShowDifferences()
1061 m_pWebDiffWindow->SetShowDifferences(m_wndWebPageDiffBar.IsDlgButtonChecked(IDC_SHOWDIFFERENCES));
1062 UpdateWebPageDiffBar();
1065 void CWebPageDiffFrame::OnBnClickedCompare()
1070 void CWebPageDiffFrame::OnDropDownCompare(NMHDR *pNMHDR, LRESULT *pResult)
1073 m_wndWebPageDiffBar.GetDlgItem(IDC_COMPARE)->GetWindowRect(&rc);
1074 CPoint point { rc.left, rc.bottom };
1076 menuPopup.LoadMenu(MAKEINTRESOURCE(IDR_POPUP_WEBPAGE_COMPARE));
1077 theApp.TranslateMenu(menuPopup.m_hMenu);
1078 BCMenu* pPopup = (BCMenu*)menuPopup.GetSubMenu(0);
1079 pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON,
1080 point.x, point.y, AfxGetMainWnd());
1083 void CWebPageDiffFrame::OnEnChangeWidth()
1085 if (m_bInUpdateWebPageDiffBar)
1088 m_wndWebPageDiffBar.GetDlgItemText(IDC_WIDTH, text);
1089 int v = _ttoi(text.c_str());
1090 if (v > 0 && v < 32678)
1092 SIZE size = m_pWebDiffWindow->GetSize();
1094 m_pWebDiffWindow->SetSize(size);
1098 void CWebPageDiffFrame::OnEnChangeHeight()
1100 if (m_bInUpdateWebPageDiffBar)
1103 m_wndWebPageDiffBar.GetDlgItemText(IDC_HEIGHT, text);
1104 int v = _ttoi(text.c_str());
1105 if (v > 0 && v < 32678)
1107 SIZE size = m_pWebDiffWindow->GetSize();
1109 m_pWebDiffWindow->SetSize(size);
1113 void CWebPageDiffFrame::OnEnChangeZoom()
1115 if (m_bInUpdateWebPageDiffBar)
1118 m_wndWebPageDiffBar.GetDlgItemText(IDC_ZOOM, text);
1119 TCHAR* endptr = nullptr;
1120 double v = _tcstod(text.c_str(), &endptr);
1121 if ((* endptr == '\0' || *endptr == '%') && v >= 25.0 && v <= 500.0)
1122 m_pWebDiffWindow->SetZoom(v / 100.0);
1125 void CWebPageDiffFrame::OnEnChangeUserAgent()
1127 if (m_bInUpdateWebPageDiffBar)
1130 m_wndWebPageDiffBar.GetDlgItemText(IDC_USERAGENT, text);
1131 m_pWebDiffWindow->SetUserAgent(text.c_str());
1134 void CWebPageDiffFrame::OnKillFocusBarControls()
1136 UpdateWebPageDiffBar();
1139 m_wndFilePathBar.GetDlgItemTextW(IDC_USERAGENT, text);
1142 void CWebPageDiffFrame::OnUpdateStatusNum(CCmdUI* pCmdUI)
1144 TCHAR sIdx[32] = { 0 };
1145 TCHAR sCnt[32] = { 0 };
1147 const int nDiffs = m_pWebDiffWindow->GetDiffCount();
1149 // Files are identical - show text "Identical"
1151 s = theApp.LoadString(IDS_IDENTICAL);
1153 // There are differences, but no selected diff
1154 // - show amount of diffs
1155 else if (m_pWebDiffWindow->GetCurrentDiffIndex() < 0)
1157 s = theApp.LoadString(nDiffs == 1 ? IDS_1_DIFF_FOUND : IDS_NO_DIFF_SEL_FMT);
1158 _itot_s(nDiffs, sCnt, 10);
1159 strutils::replace(s, _T("%1"), sCnt);
1162 // There are differences and diff selected
1163 // - show diff number and amount of diffs
1166 s = theApp.LoadString(IDS_DIFF_NUMBER_STATUS_FMT);
1167 const int signInd = m_pWebDiffWindow->GetCurrentDiffIndex();
1168 _itot_s(signInd + 1, sIdx, 10);
1169 strutils::replace(s, _T("%1"), sIdx);
1170 _itot_s(nDiffs, sCnt, 10);
1171 strutils::replace(s, _T("%2"), sCnt);
1173 pCmdUI->SetText(s.c_str());
1177 * @brief Cut current selection to clipboard
1179 void CWebPageDiffFrame::OnEditCut()
1181 m_pWebDiffWindow->Cut();
1185 * @brief Copy current selection to clipboard
1187 void CWebPageDiffFrame::OnEditCopy()
1189 m_pWebDiffWindow->Copy();
1193 * @brief Paste clipboard content over selected content
1195 void CWebPageDiffFrame::OnEditPaste()
1197 m_pWebDiffWindow->Paste();
1201 * @brief Undo last action
1203 void CWebPageDiffFrame::OnEditUndo()
1205 m_pWebDiffWindow->Undo();
1209 * @brief Redo last action
1211 void CWebPageDiffFrame::OnEditRedo()
1213 m_pWebDiffWindow->Redo();
1217 * @brief Update the tool bar's "Undo" icon. It should be enabled when
1218 * renaming an item and undo is possible.
1220 void CWebPageDiffFrame::OnUpdateEditUndo(CCmdUI* pCmdUI)
1222 pCmdUI->Enable(m_pWebDiffWindow->CanUndo());
1226 * @brief Update the tool bar's "Redo" icon. It should be enabled when
1227 * renaming an item and undo is possible.
1229 void CWebPageDiffFrame::OnUpdateEditRedo(CCmdUI* pCmdUI)
1231 pCmdUI->Enable(m_pWebDiffWindow->CanRedo());
1235 * @brief Select entire image
1237 void CWebPageDiffFrame::OnEditSelectAll()
1239 m_pWebDiffWindow->SelectAll();
1243 * @brief Called when user selects View/Zoom In from menu.
1245 void CWebPageDiffFrame::OnViewZoomIn()
1247 m_pWebDiffWindow->SetZoom(m_pWebDiffWindow->GetZoom() + 0.1);
1251 * @brief Called when user selects View/Zoom Out from menu.
1253 void CWebPageDiffFrame::OnViewZoomOut()
1255 m_pWebDiffWindow->SetZoom(m_pWebDiffWindow->GetZoom() - 0.1);
1259 * @brief Called when user selects View/Zoom Normal from menu.
1261 void CWebPageDiffFrame::OnViewZoomNormal()
1263 m_pWebDiffWindow->SetZoom(1.0);
1267 * @brief Enables/disables linediff (different color for diffs)
1269 void CWebPageDiffFrame::OnViewLineDiffs()
1271 bool bWordDiffHighlight = !GetOptionsMgr()->GetBool(OPT_WORDDIFF_HIGHLIGHT);
1272 GetOptionsMgr()->SaveOption(OPT_WORDDIFF_HIGHLIGHT, bWordDiffHighlight);
1273 m_pWebDiffWindow->SetShowWordDifferences(bWordDiffHighlight);
1276 void CWebPageDiffFrame::OnUpdateViewLineDiffs(CCmdUI* pCmdUI)
1278 pCmdUI->Enable(true);
1279 pCmdUI->SetCheck(GetOptionsMgr()->GetBool(OPT_WORDDIFF_HIGHLIGHT));
1283 * @brief Split panes vertically
1285 void CWebPageDiffFrame::OnViewSplitVertically()
1287 bool bSplitVertically = !m_pWebDiffWindow->GetHorizontalSplit();
1288 bSplitVertically = !bSplitVertically; // toggle
1289 GetOptionsMgr()->SaveOption(OPT_SPLIT_HORIZONTALLY, !bSplitVertically);
1290 m_pWebDiffWindow->SetHorizontalSplit(!bSplitVertically);
1294 * @brief Update "Split Vertically" UI items
1296 void CWebPageDiffFrame::OnUpdateViewSplitVertically(CCmdUI* pCmdUI)
1298 pCmdUI->Enable(TRUE);
1299 pCmdUI->SetCheck(!m_pWebDiffWindow->GetHorizontalSplit());
1303 * @brief Go to first diff
1305 * Called when user selects "First Difference"
1306 * @sa CWebPageDiffFrame::SelectDiff()
1308 void CWebPageDiffFrame::OnFirstdiff()
1310 m_pWebDiffWindow->FirstDiff();
1314 * @brief Update "First diff" UI items
1316 void CWebPageDiffFrame::OnUpdateFirstdiff(CCmdUI* pCmdUI)
1318 OnUpdatePrevdiff(pCmdUI);
1322 * @brief Go to last diff
1324 void CWebPageDiffFrame::OnLastdiff()
1326 m_pWebDiffWindow->LastDiff();
1330 * @brief Update "Last diff" UI items
1332 void CWebPageDiffFrame::OnUpdateLastdiff(CCmdUI* pCmdUI)
1334 OnUpdateNextdiff(pCmdUI);
1338 * @brief Go to next diff and select it.
1340 void CWebPageDiffFrame::OnNextdiff()
1342 if (m_pWebDiffWindow->GetCurrentDiffIndex() != m_pWebDiffWindow->GetDiffCount() - 1)
1343 m_pWebDiffWindow->NextDiff();
1344 else if (m_pDirDoc != nullptr)
1345 m_pDirDoc->MoveToNextDiff(this);
1349 * @brief Update "Next diff" UI items
1351 void CWebPageDiffFrame::OnUpdateNextdiff(CCmdUI* pCmdUI)
1353 bool enabled = m_bCompareCompleted && (
1354 m_pWebDiffWindow->GetNextDiffIndex() >= 0 ||
1355 (m_pWebDiffWindow->GetDiffCount() > 0 && m_pWebDiffWindow->GetCurrentDiffIndex() == -1));
1357 if (!enabled && m_pDirDoc != nullptr)
1358 enabled = m_pDirDoc->MoveableToNextDiff();
1359 pCmdUI->Enable(enabled);
1363 * @brief Go to previous diff and select it.
1365 void CWebPageDiffFrame::OnPrevdiff()
1367 if (m_pWebDiffWindow->GetCurrentDiffIndex() > 0)
1369 m_pWebDiffWindow->PrevDiff();
1371 else if (m_pDirDoc != nullptr)
1372 m_pDirDoc->MoveToPrevDiff(this);
1376 * @brief Update "Previous diff" UI items
1378 void CWebPageDiffFrame::OnUpdatePrevdiff(CCmdUI* pCmdUI)
1380 bool enabled = m_bCompareCompleted && (
1381 m_pWebDiffWindow->GetPrevDiffIndex() >= 0 ||
1382 (m_pWebDiffWindow->GetDiffCount() > 0 && m_pWebDiffWindow->GetCurrentDiffIndex() == -1));
1384 if (!enabled && m_pDirDoc != nullptr)
1385 enabled = m_pDirDoc->MoveableToPrevDiff();
1386 pCmdUI->Enable(enabled);
1390 * @brief Go to next conflict and select it.
1392 void CWebPageDiffFrame::OnNextConflict()
1394 m_pWebDiffWindow->NextConflict();
1398 * @brief Update "Next Conflict" UI items
1400 void CWebPageDiffFrame::OnUpdateNextConflict(CCmdUI* pCmdUI)
1402 pCmdUI->Enable(m_bCompareCompleted &&
1403 m_pWebDiffWindow->GetPaneCount() > 2 && (
1404 m_pWebDiffWindow->GetNextConflictIndex() >= 0 ||
1405 (m_pWebDiffWindow->GetConflictCount() > 0 && m_pWebDiffWindow->GetCurrentDiffIndex() == -1)
1411 * @brief Go to previous diff and select it.
1413 void CWebPageDiffFrame::OnPrevConflict()
1415 m_pWebDiffWindow->PrevConflict();
1419 * @brief Update "Previous diff" UI items
1421 void CWebPageDiffFrame::OnUpdatePrevConflict(CCmdUI* pCmdUI)
1423 pCmdUI->Enable(m_bCompareCompleted &&
1424 m_pWebDiffWindow->GetPaneCount() > 2 && (
1425 m_pWebDiffWindow->GetPrevConflictIndex() >= 0 ||
1426 (m_pWebDiffWindow->GetConflictCount() > 0 && m_pWebDiffWindow->GetCurrentDiffIndex() == -1)
1431 void CWebPageDiffFrame::OnWebFitToWindow()
1433 m_pWebDiffWindow->SetFitToWindow(true);
1435 UpdateWebPageDiffBar();
1438 void CWebPageDiffFrame::OnUpdateWebFitToWindow(CCmdUI* pCmdUI)
1440 pCmdUI->SetCheck(m_pWebDiffWindow->GetFitToWindow());
1443 void CWebPageDiffFrame::OnWebSize(UINT nID)
1447 case ID_WEB_SIZE_320x512:
1448 m_pWebDiffWindow->SetFitToWindow(false);
1449 m_pWebDiffWindow->SetSize({ 320, 512 });
1450 UpdateWebPageDiffBar();
1452 case ID_WEB_SIZE_375x600:
1453 m_pWebDiffWindow->SetFitToWindow(false);
1454 m_pWebDiffWindow->SetSize({ 375, 600 });
1455 UpdateWebPageDiffBar();
1457 case ID_WEB_SIZE_1024x640:
1458 m_pWebDiffWindow->SetFitToWindow(false);
1459 m_pWebDiffWindow->SetSize({ 1024, 640 });
1461 UpdateWebPageDiffBar();
1463 case ID_WEB_SIZE_1280x800:
1464 m_pWebDiffWindow->SetFitToWindow(false);
1465 m_pWebDiffWindow->SetSize({ 1280, 800 });
1467 UpdateWebPageDiffBar();
1469 case ID_WEB_SIZE_1440x900:
1470 m_pWebDiffWindow->SetFitToWindow(false);
1471 m_pWebDiffWindow->SetSize({ 1440, 900 });
1473 UpdateWebPageDiffBar();
1478 void CWebPageDiffFrame::OnWebCompareScreenshots(UINT nID)
1480 std::shared_ptr<CWaitCursor> pWaitStatus{ new CWaitCursor() };
1482 const wchar_t *spaths[3];
1483 std::vector<String> descs;
1484 const int nPanes = m_pWebDiffWindow->GetPaneCount();
1485 for (int pane = 0; pane < nPanes; ++pane)
1487 std::shared_ptr<TempFile> pTempFile(new TempFile());
1488 pTempFile->Create(_T("SCR"), _T(".png"));
1489 paths.SetPath(pane, pTempFile->GetPath());
1490 spaths[pane] = paths[pane].c_str();
1491 descs.push_back(m_filePaths[pane]);
1492 m_tempFiles.push_back(pTempFile);
1494 m_pWebDiffWindow->SaveFiles(
1495 (nID == ID_WEB_COMPARE_FULLSIZE_SCREENSHOTS) ? IWebDiffWindow::FULLSIZE_SCREENSHOT : IWebDiffWindow::SCREENSHOT,
1497 Callback<IWebDiffCallback>([paths, descs, pWaitStatus](const WebDiffCallbackResult& result) -> HRESULT
1499 DWORD dwFlags[3] = { FFILEOPEN_NOMRU, FFILEOPEN_NOMRU, FFILEOPEN_NOMRU };
1500 GetMainFrame()->DoFileOpen(0, &paths, dwFlags, descs.data());
1505 void CWebPageDiffFrame::OnWebCompareHTMLs()
1507 std::shared_ptr<CWaitCursor> pWaitStatus{ new CWaitCursor() };
1509 const wchar_t *spaths[3];
1510 std::vector<String> descs;
1511 const int nPanes = m_pWebDiffWindow->GetPaneCount();
1512 for (int pane = 0; pane < nPanes; ++pane)
1514 std::shared_ptr<TempFile> pTempFile(new TempFile());
1515 pTempFile->Create(_T("HTM"), _T(".html"));
1516 paths.SetPath(pane, pTempFile->GetPath());
1517 spaths[pane] = paths[pane].c_str();
1518 descs.push_back(m_filePaths[pane]);
1519 m_tempFiles.push_back(pTempFile);
1521 m_pWebDiffWindow->SaveFiles(IWebDiffWindow::HTML, spaths,
1522 Callback<IWebDiffCallback>([paths, descs, pWaitStatus](const WebDiffCallbackResult& result) -> HRESULT
1524 PackingInfo infoUnpacker(String(_T("PrettifyHTML")));
1525 DWORD dwFlags[3] = { FFILEOPEN_NOMRU, FFILEOPEN_NOMRU, FFILEOPEN_NOMRU };
1526 GetMainFrame()->DoFileOpen(0, &paths, dwFlags, descs.data(), _T(""), &infoUnpacker);
1531 void CWebPageDiffFrame::OnWebCompareTexts()
1533 std::shared_ptr<CWaitCursor> pWaitStatus{ new CWaitCursor() };
1535 const wchar_t *spaths[3];
1536 std::vector<String> descs;
1537 const int nPanes = m_pWebDiffWindow->GetPaneCount();
1538 for (int pane = 0; pane < nPanes; ++pane)
1540 std::shared_ptr<TempFile> pTempFile(new TempFile());
1541 pTempFile->Create(_T("TXT"), _T(".txt"));
1542 paths.SetPath(pane, pTempFile->GetPath());
1543 spaths[pane] = paths[pane].c_str();
1544 descs.push_back(m_filePaths[pane]);
1545 m_tempFiles.push_back(pTempFile);
1547 m_pWebDiffWindow->SaveFiles(IWebDiffWindow::TEXT, spaths,
1548 Callback<IWebDiffCallback>([paths, descs, pWaitStatus](const WebDiffCallbackResult& result) -> HRESULT
1550 DWORD dwFlags[3] = { FFILEOPEN_NOMRU, FFILEOPEN_NOMRU, FFILEOPEN_NOMRU };
1551 GetMainFrame()->DoFileOpen(0, &paths, dwFlags, descs.data(), _T(""));
1556 void CWebPageDiffFrame::OnWebCompareResourceTrees()
1558 std::shared_ptr<CWaitCursor> pWaitStatus{ new CWaitCursor() };
1560 const wchar_t *spaths[3];
1561 std::vector<String> descs;
1562 const int nPanes = m_pWebDiffWindow->GetPaneCount();
1563 for (int pane = 0; pane < nPanes; ++pane)
1565 std::shared_ptr<TempFolder> pTempFolder(new TempFolder());
1566 pTempFolder->Create();
1567 paths.SetPath(pane, pTempFolder->GetPath());
1568 spaths[pane] = paths[pane].c_str();
1569 descs.push_back(m_filePaths[pane]);
1570 m_tempFolders.push_back(pTempFolder);
1572 m_pWebDiffWindow->SaveFiles(IWebDiffWindow::RESOURCETREE, spaths,
1573 Callback<IWebDiffCallback>([paths, descs, pWaitStatus](const WebDiffCallbackResult& result) -> HRESULT
1576 for (int pane = 0; pane < paths.GetSize(); ++pane)
1577 dwFlags[pane] = FFILEOPEN_NOMRU;
1578 GetMainFrame()->DoFileOrFolderOpen(&paths, dwFlags, descs.data(), _T(""), true);
1583 void CWebPageDiffFrame::OnWebClear(UINT nID)
1585 IWebDiffWindow::BrowsingDataType dataKinds;
1588 case ID_WEB_CLEAR_DISK_CACHE: dataKinds = IWebDiffWindow::BrowsingDataType::DISK_CACHE; break;
1589 case ID_WEB_CLEAR_COOKIES: dataKinds = IWebDiffWindow::BrowsingDataType::COOKIES; break;
1590 case ID_WEB_CLEAR_BROWSING_HISTORY: dataKinds = IWebDiffWindow::BrowsingDataType::BROWSING_HISTORY; break;
1591 case ID_WEB_CLEAR_ALL_PROFILE: dataKinds = IWebDiffWindow::BrowsingDataType::ALL_PROFILE; break;
1595 m_pWebDiffWindow->ClearBrowsingData(-1, dataKinds);
1598 bool CWebPageDiffFrame::GenerateReport(const String& sFileName) const
1600 //return GenerateReport(sFileName, true);
1605 // * @brief Generate report from file compare results.
1607 //bool CWebPageDiffFrame::GenerateReport(const String& sFileName, bool allPages) const
1613 // * @brief Generate report from file compare results.
1615 //void CWebPageDiffFrame::OnToolsGenerateReport()
1619 void CWebPageDiffFrame::OnRefresh()
1621 if (!m_bCompareCompleted)
1623 m_bCompareCompleted = false;
1624 m_pWebDiffWindow->Recompare(
1625 Callback<IWebDiffCallback>([this](const WebDiffCallbackResult& result) -> HRESULT
1627 m_bCompareCompleted = true;
1628 if (UpdateDiffItem(m_pDirDoc) == 0 &&
1629 std::count(m_filePaths.begin(), m_filePaths.end(), L"about:blank") != m_filePaths.GetSize())
1631 CMergeFrameCommon::ShowIdenticalMessage(m_filePaths, true,
1632 [](LPCTSTR msg, UINT flags, UINT id) -> int { return AfxMessageBox(msg, flags, id); });
1639 void CWebPageDiffFrame::OnSetFocus(CWnd* pNewWnd)
1641 if (m_nActivePane != -1)
1642 m_pWebDiffWindow->SetActivePane(m_nActivePane);
1646 * @brief Open help from mainframe when user presses F1
1648 void CWebPageDiffFrame::OnHelp()
1650 theApp.ShowHelp(WebPageDiffFrameHelpLocation);