X-Git-Url: http://git.osdn.net/view?a=blobdiff_plain;f=Src%2FMainFrm.cpp;h=708ddb4f3d362a20b54cc595cbd5d1f017c078ca;hb=40c7433ddcc7ada26335a0f66470636b5d102e9f;hp=f9df628ae7435abef1dfa562088e26bc1f7dd55d;hpb=e8f213521bc492152efa393712203f02886b92b7;p=winmerge-jp%2Fwinmerge-jp.git diff --git a/Src/MainFrm.cpp b/Src/MainFrm.cpp index f9df628ae..708ddb4f3 100644 --- a/Src/MainFrm.cpp +++ b/Src/MainFrm.cpp @@ -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 MainFrm.cpp @@ -36,7 +22,7 @@ #include "BCMenu.h" #include "OpenFrm.h" #include "DirFrame.h" // Include type information -#include "ChildFrm.h" +#include "MergeEditFrm.h" #include "HexMergeFrm.h" #include "DirView.h" #include "DirDoc.h" @@ -47,8 +33,10 @@ #include "HexMergeView.h" #include "ImgMergeFrm.h" #include "LineFiltersList.h" +#include "SubstitutionFiltersList.h" #include "ConflictFileParser.h" #include "LineFiltersDlg.h" +#include "SubstitutionFiltersDlg.h" #include "paths.h" #include "Environment.h" #include "PatchTool.h" @@ -73,6 +61,11 @@ #include "VersionInfo.h" #include "Bitmap.h" #include "CCrystalTextMarkers.h" +#include "utils/hqbitmap.h" +#include "UniFile.h" +#include "TFile.h" +#include "Shell.h" +#include "WindowsManagerDialog.h" using std::vector; using boost::begin; @@ -82,17 +75,23 @@ using boost::end; #define new DEBUG_NEW #endif -static void LoadToolbarImageList(int imageWidth, UINT nIDResource, UINT nIDResourceMask, bool bGrayscale, CImageList& ImgList); +static void LoadToolbarImageList(int orgImageWidth, int newImageHeight, UINT nIDResource, bool bGrayscale, CImageList& ImgList); static CPtrList &GetDocList(CMultiDocTemplate *pTemplate); template -DocClass * GetMergeDocForDiff(CMultiDocTemplate *pTemplate, CDirDoc *pDirDoc, int nFiles); +DocClass * GetMergeDocForDiff(CMultiDocTemplate *pTemplate, CDirDoc *pDirDoc, int nFiles, bool bMakeVisible = true); /** * @brief A table associating menuitem id, icon and menus to apply. */ const CMainFrame::MENUITEM_ICON CMainFrame::m_MenuIcons[] = { { ID_FILE_OPENCONFLICT, IDB_FILE_OPENCONFLICT, CMainFrame::MENU_ALL }, - { ID_FILE_NEW3, IDB_FILE_NEW3, CMainFrame::MENU_ALL }, + { ID_FILE_NEW_TABLE, IDB_FILE_NEW_TABLE, CMainFrame::MENU_ALL }, + { ID_FILE_NEW_HEX, IDB_FILE_NEW_HEX, CMainFrame::MENU_ALL }, + { ID_FILE_NEW_IMAGE, IDB_FILE_NEW_IMAGE, CMainFrame::MENU_ALL }, + { ID_FILE_NEW3, IDB_FILE_NEW3, CMainFrame::MENU_ALL }, + { ID_FILE_NEW3_TABLE, IDB_FILE_NEW3_TABLE, CMainFrame::MENU_ALL }, + { ID_FILE_NEW3_HEX, IDB_FILE_NEW3_HEX, CMainFrame::MENU_ALL }, + { ID_FILE_NEW3_IMAGE, IDB_FILE_NEW3_IMAGE, CMainFrame::MENU_ALL }, { ID_EDIT_COPY, IDB_EDIT_COPY, CMainFrame::MENU_ALL }, { ID_EDIT_CUT, IDB_EDIT_CUT, CMainFrame::MENU_ALL }, { ID_EDIT_PASTE, IDB_EDIT_PASTE, CMainFrame::MENU_ALL }, @@ -112,8 +111,6 @@ const CMainFrame::MENUITEM_ICON CMainFrame::m_MenuIcons[] = { { ID_TOOLS_CUSTOMIZECOLUMNS, IDB_TOOLS_COLUMNS, CMainFrame::MENU_ALL }, { ID_TOOLS_GENERATEPATCH, IDB_TOOLS_GENERATEPATCH, CMainFrame::MENU_ALL }, { ID_PLUGINS_LIST, IDB_PLUGINS_LIST, CMainFrame::MENU_ALL }, - { ID_COPY_FROM_LEFT, IDB_COPY_FROM_LEFT, CMainFrame::MENU_ALL }, - { ID_COPY_FROM_RIGHT, IDB_COPY_FROM_RIGHT, CMainFrame::MENU_ALL }, { ID_FILE_PRINT, IDB_FILE_PRINT, CMainFrame::MENU_FILECMP }, { ID_TOOLS_GENERATEREPORT, IDB_TOOLS_GENERATEREPORT, CMainFrame::MENU_FILECMP }, { ID_EDIT_TOGGLE_BOOKMARK, IDB_EDIT_TOGGLE_BOOKMARK, CMainFrame::MENU_FILECMP }, @@ -122,6 +119,12 @@ const CMainFrame::MENUITEM_ICON CMainFrame::m_MenuIcons[] = { { ID_EDIT_CLEAR_ALL_BOOKMARKS, IDB_EDIT_CLEAR_ALL_BOOKMARKS, CMainFrame::MENU_FILECMP }, { ID_VIEW_ZOOMIN, IDB_VIEW_ZOOMIN, CMainFrame::MENU_FILECMP }, { ID_VIEW_ZOOMOUT, IDB_VIEW_ZOOMOUT, CMainFrame::MENU_FILECMP }, + { ID_COPY_FROM_LEFT, IDB_COPY_FROM_LEFT, CMainFrame::MENU_FILECMP }, + { ID_COPY_FROM_RIGHT, IDB_COPY_FROM_RIGHT, CMainFrame::MENU_FILECMP }, + { ID_LINES_R2L, IDB_COPY_SELECTED_LINES_TO_LEFT, CMainFrame::MENU_FILECMP }, + { ID_LINES_L2R, IDB_COPY_SELECTED_LINES_TO_RIGHT, CMainFrame::MENU_FILECMP }, + { ID_COPY_LINES_FROM_LEFT, IDB_COPY_SELECTED_LINES_FROM_LEFT, CMainFrame::MENU_FILECMP }, + { ID_COPY_LINES_FROM_RIGHT, IDB_COPY_SELECTED_LINES_FROM_RIGHT, CMainFrame::MENU_FILECMP }, { ID_MERGE_COMPARE, IDB_MERGE_COMPARE, CMainFrame::MENU_FOLDERCMP }, { ID_MERGE_COMPARE_LEFT1_LEFT2, IDB_MERGE_COMPARE_LEFT1_LEFT2, CMainFrame::MENU_FOLDERCMP }, { ID_MERGE_COMPARE_RIGHT1_RIGHT2, IDB_MERGE_COMPARE_RIGHT1_RIGHT2,CMainFrame::MENU_FOLDERCMP }, @@ -184,6 +187,7 @@ BEGIN_MESSAGE_MAP(CMainFrame, CMDIFrameWnd) ON_COMMAND(ID_HELP_CONTENTS, OnHelpContents) ON_WM_CLOSE() ON_COMMAND(ID_TOOLS_GENERATEPATCH, OnToolsGeneratePatch) + ON_WM_TIMER() ON_WM_DESTROY() ON_COMMAND_RANGE(ID_UNPACK_MANUAL, ID_UNPACK_AUTO, OnPluginUnpackMode) ON_UPDATE_COMMAND_UI_RANGE(ID_UNPACK_MANUAL, ID_UNPACK_AUTO, OnUpdatePluginUnpackMode) @@ -192,8 +196,14 @@ BEGIN_MESSAGE_MAP(CMainFrame, CMDIFrameWnd) ON_UPDATE_COMMAND_UI(ID_RELOAD_PLUGINS, OnUpdateReloadPlugins) ON_COMMAND(ID_RELOAD_PLUGINS, OnReloadPlugins) ON_COMMAND(ID_HELP_GETCONFIG, OnSaveConfigData) - ON_COMMAND(ID_FILE_NEW, OnFileNew) - ON_COMMAND(ID_FILE_NEW3, OnFileNew3) + ON_COMMAND(ID_FILE_NEW, (OnFileNew<2, FRAME_FILE>)) + ON_COMMAND(ID_FILE_NEW_TABLE, (OnFileNew<2, FRAME_FILE, true>)) + ON_COMMAND(ID_FILE_NEW_HEX, (OnFileNew<2, FRAME_HEXFILE>)) + ON_COMMAND(ID_FILE_NEW_IMAGE, (OnFileNew<2, FRAME_IMGFILE>)) + ON_COMMAND(ID_FILE_NEW3, (OnFileNew<3, FRAME_FILE>)) + ON_COMMAND(ID_FILE_NEW3_TABLE, (OnFileNew<2, FRAME_FILE, true>)) + ON_COMMAND(ID_FILE_NEW3_HEX, (OnFileNew<3, FRAME_HEXFILE>)) + ON_COMMAND(ID_FILE_NEW3_IMAGE, (OnFileNew<3, FRAME_IMGFILE>)) ON_COMMAND(ID_TOOLS_FILTERS, OnToolsFilters) ON_COMMAND(ID_VIEW_STATUS_BAR, OnViewStatusBar) ON_UPDATE_COMMAND_UI(ID_VIEW_TAB_BAR, OnUpdateViewTabBar) @@ -216,13 +226,15 @@ BEGIN_MESSAGE_MAP(CMainFrame, CMDIFrameWnd) ON_COMMAND(ID_FILE_OPENCONFLICT, OnFileOpenConflict) ON_COMMAND(ID_PLUGINS_LIST, OnPluginsList) ON_UPDATE_COMMAND_UI(ID_STATUS_PLUGIN, OnUpdatePluginName) - ON_NOTIFY(TBN_DROPDOWN, AFX_IDW_TOOLBAR, OnDiffOptionsDropDown) + ON_NOTIFY(TBN_DROPDOWN, AFX_IDW_TOOLBAR, OnToolbarButtonDropDown) ON_COMMAND_RANGE(IDC_DIFF_WHITESPACE_COMPARE, IDC_DIFF_WHITESPACE_IGNOREALL, OnDiffWhitespace) ON_UPDATE_COMMAND_UI_RANGE(IDC_DIFF_WHITESPACE_COMPARE, IDC_DIFF_WHITESPACE_IGNOREALL, OnUpdateDiffWhitespace) - ON_COMMAND(IDC_DIFF_CASESENSITIVE, OnDiffCaseSensitive) - ON_UPDATE_COMMAND_UI(IDC_DIFF_CASESENSITIVE, OnUpdateDiffCaseSensitive) + ON_COMMAND(IDC_DIFF_IGNORECASE, OnDiffIgnoreCase) + ON_UPDATE_COMMAND_UI(IDC_DIFF_IGNORECASE, OnUpdateDiffIgnoreCase) ON_COMMAND(IDC_DIFF_IGNOREEOL, OnDiffIgnoreEOL) ON_UPDATE_COMMAND_UI(IDC_DIFF_IGNOREEOL, OnUpdateDiffIgnoreEOL) + ON_COMMAND(IDC_DIFF_IGNORECP, OnDiffIgnoreCP) + ON_UPDATE_COMMAND_UI(IDC_DIFF_IGNORECP, OnUpdateDiffIgnoreCP) ON_COMMAND(IDC_RECURS_CHECK, OnIncludeSubfolders) ON_UPDATE_COMMAND_UI(IDC_RECURS_CHECK, OnUpdateIncludeSubfolders) ON_COMMAND_RANGE(ID_COMPMETHOD_FULL_CONTENTS, ID_COMPMETHOD_SIZE, OnCompareMethod) @@ -230,6 +242,19 @@ BEGIN_MESSAGE_MAP(CMainFrame, CMDIFrameWnd) ON_COMMAND_RANGE(ID_MRU_FIRST, ID_MRU_LAST, OnMRUs) ON_UPDATE_COMMAND_UI(ID_MRU_FIRST, OnUpdateNoMRUs) ON_UPDATE_COMMAND_UI(ID_NO_MRU, OnUpdateNoMRUs) + ON_COMMAND(ID_FIRSTFILE, OnFirstFile) + ON_UPDATE_COMMAND_UI(ID_FIRSTFILE, OnUpdateFirstFile) + ON_COMMAND(ID_PREVFILE, OnPrevFile) + ON_UPDATE_COMMAND_UI(ID_PREVFILE, OnUpdatePrevFile) + ON_COMMAND(ID_NEXTFILE, OnNextFile) + ON_UPDATE_COMMAND_UI(ID_NEXTFILE, OnUpdateNextFile) + ON_COMMAND(ID_LASTFILE, OnLastFile) + ON_UPDATE_COMMAND_UI(ID_LASTFILE, OnUpdateLastFile) + ON_COMMAND(ID_ACCEL_QUIT, &CMainFrame::OnAccelQuit) + ON_MESSAGE(WMU_CHILDFRAMEADDED, &CMainFrame::OnChildFrameAdded) + ON_MESSAGE(WMU_CHILDFRAMEREMOVED, &CMainFrame::OnChildFrameRemoved) + ON_MESSAGE(WMU_CHILDFRAMEACTIVATE, &CMainFrame::OnChildFrameActivate) + ON_MESSAGE(WMU_CHILDFRAMEACTIVATED, &CMainFrame::OnChildFrameActivated) //}}AFX_MSG_MAP END_MESSAGE_MAP() @@ -269,8 +294,10 @@ static CPtrList &GetDocList(CMultiDocTemplate *pTemplate) */ CMainFrame::CMainFrame() : m_bFirstTime(true) -, m_pDropHandler(NULL) +, m_pDropHandler(nullptr) , m_bShowErrors(false) +, m_lfDiff(Options::Font::Load(GetOptionsMgr(), OPT_FONT_FILECMP)) +, m_lfDir(Options::Font::Load(GetOptionsMgr(), OPT_FONT_DIRCMP)) { } @@ -278,13 +305,12 @@ CMainFrame::~CMainFrame() { GetOptionsMgr()->SaveOption(OPT_TABBAR_AUTO_MAXWIDTH, m_wndTabBar.GetAutoMaxWidth()); strdiff::Close(); + + m_arrChild.RemoveAll(); } -#ifdef _UNICODE const TCHAR CMainFrame::szClassName[] = _T("WinMergeWindowClassW"); -#else -const TCHAR CMainFrame::szClassName[] = _T("WinMergeWindowClassA"); -#endif + /** * @brief Change MainFrame window class name * see http://support.microsoft.com/kb/403825/ja @@ -313,9 +339,8 @@ int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) if (CMDIFrameWnd::OnCreate(lpCreateStruct) == -1) return -1; - m_lfDiff = Options::Font::Load(GetOptionsMgr(), OPT_FONT_FILECMP); - m_lfDir = Options::Font::Load(GetOptionsMgr(), OPT_FONT_DIRCMP); - + m_wndMDIClient.SubclassWindow(m_hWndMDIClient); + if (!CreateToolbar()) { TRACE0("Failed to create toolbar\n"); @@ -338,7 +363,7 @@ int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) return -1; // fail to create } theApp.SetIndicators(m_wndStatusBar, StatusbarIndicators, - countof(StatusbarIndicators)); + static_cast(std::size(StatusbarIndicators))); const int lpx = CClientDC(this).GetDeviceCaps(LOGPIXELSX); auto pointToPixel = [lpx](int point) { return MulDiv(point, lpx, 72); }; @@ -353,40 +378,68 @@ int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) m_pDropHandler = new DropHandler(std::bind(&CMainFrame::OnDropFiles, this, std::placeholders::_1)); RegisterDragDrop(m_hWnd, m_pDropHandler); + m_wndMDIClient.ModifyStyleEx(WS_EX_CLIENTEDGE, 0); + return 0; } +void CMainFrame::OnTimer(UINT_PTR nIDEvent) +{ + CMDIFrameWnd::OnTimer(nIDEvent); + + if (nIDEvent == IDT_UPDATEMAINMENU) + { + KillTimer(nIDEvent); + + BOOL bMaximized; + MDIGetActive(&bMaximized); + + // When MDI maximized the window icon is drawn on the menu bar, so we + // need to notify it that our icon has changed. + if (bMaximized) + DrawMenuBar(); + + OnUpdateFrameTitle(FALSE); + } +} + void CMainFrame::OnDestroy(void) { - if (m_pDropHandler) + if (m_pDropHandler != nullptr) RevokeDragDrop(m_hWnd); } -static HMENU GetSubmenu(HMENU mainMenu, UINT nIDFirstMenuItem, bool bFirstSubmenu) +static HMENU GetSubmenu(HMENU menu, bool bFirstSubmenu) { - int i; - for (i = 0 ; i < ::GetMenuItemCount(mainMenu) ; i++) - if (::GetMenuItemID(::GetSubMenu(mainMenu, i), 0) == nIDFirstMenuItem) - break; - HMENU menu = ::GetSubMenu(mainMenu, i); - if (!bFirstSubmenu) { // look for last submenu - for (i = ::GetMenuItemCount(menu) ; i >= 0 ; i--) - if (::GetSubMenu(menu, i) != NULL) + for (int i = ::GetMenuItemCount(menu) ; i >= 0 ; i--) + if (::GetSubMenu(menu, i) != nullptr) return ::GetSubMenu(menu, i); } else { // look for first submenu - for (i = 0 ; i < ::GetMenuItemCount(menu) ; i++) - if (::GetSubMenu(menu, i) != NULL) + for (int i = 0 ; i < ::GetMenuItemCount(menu) ; i++) + if (::GetSubMenu(menu, i) != nullptr) return ::GetSubMenu(menu, i); } // error, submenu not found - return NULL; + return nullptr; +} + +static HMENU GetSubmenu(HMENU mainMenu, UINT nIDFirstMenuItem, bool bFirstSubmenu) +{ + int i; + for (i = 0 ; i < ::GetMenuItemCount(mainMenu) ; i++) + if (::GetMenuItemID(::GetSubMenu(mainMenu, i), 0) == nIDFirstMenuItem) + break; + HMENU menu = ::GetSubMenu(mainMenu, i); + if (!menu) + return nullptr; + return GetSubmenu(menu, bFirstSubmenu); } /** @@ -419,12 +472,12 @@ HMENU CMainFrame::GetPrediffersSubmenu(HMENU mainMenu) */ HMENU CMainFrame::NewMenu(int view, int ID) { - int menu_view, index; - if (m_pMenus[view] == NULL) + int menu_view; + if (m_pMenus[view] == nullptr) { m_pMenus[view].reset(new BCMenu()); - if (m_pMenus[view] == NULL) - return NULL; + if (m_pMenus[view] == nullptr) + return nullptr; } switch (view) @@ -444,22 +497,22 @@ HMENU CMainFrame::NewMenu(int view, int ID) if (!m_pMenus[view]->LoadMenu(ID)) { ASSERT(false); - return NULL; + return nullptr; } if (view == MENU_IMGMERGEVIEW) { - BCMenu *pMenu = new BCMenu; - pMenu->LoadMenu(MAKEINTRESOURCE(IDR_POPUP_IMGMERGEVIEW)); - m_pMenus[view]->InsertMenu(4, MF_BYPOSITION | MF_POPUP, (UINT_PTR)pMenu->GetSubMenu(0)->m_hMenu, const_cast(LoadResString(IDS_IMAGE_MENU).c_str())); + m_pImageMenu.reset(new BCMenu); + m_pImageMenu->LoadMenu(MAKEINTRESOURCE(IDR_POPUP_IMGMERGEVIEW)); + m_pMenus[view]->InsertMenu(4, MF_BYPOSITION | MF_POPUP, (UINT_PTR)m_pImageMenu->GetSubMenu(0)->m_hMenu, const_cast(LoadResString(IDS_IMAGE_MENU).c_str())); } // Load bitmaps to menuitems - for (index = 0; index < countof(m_MenuIcons); index ++) + for (auto& menu_icon: m_MenuIcons) { - if (menu_view == (m_MenuIcons[index].menusToApply & menu_view)) + if (menu_view == (menu_icon.menusToApply & menu_view)) { - m_pMenus[view]->ModifyODMenu(NULL, m_MenuIcons[index].menuitemID, m_MenuIcons[index].iconResID); + m_pMenus[view]->ModifyODMenu(nullptr, menu_icon.menuitemID, menu_icon.iconResID); } } @@ -557,7 +610,7 @@ LRESULT CMainFrame::OnMenuChar(UINT nChar, UINT nFlags, lresult=BCMenu::FindKeyboardShortcut(nChar, nFlags, pMenu); else lresult=CMDIFrameWnd::OnMenuChar(nChar, nFlags, pMenu); - return(lresult); + return lresult; } /** @@ -592,28 +645,67 @@ void CMainFrame::OnFileOpen() static void FileLocationGuessEncodings(FileLocation & fileloc, int iGuessEncoding) { - fileloc.encoding = GuessCodepageEncoding(fileloc.filepath, iGuessEncoding); + fileloc.encoding = codepage_detect::Guess(fileloc.filepath, iGuessEncoding); } bool CMainFrame::ShowAutoMergeDoc(CDirDoc * pDirDoc, int nFiles, const FileLocation ifileloc[], - const DWORD dwFlags[], const String strDesc[], const String& sReportFile /*=_T("")*/, - const PackingInfo * infoUnpacker /*= NULL*/) + const DWORD dwFlags[], const String strDesc[], const String& sReportFile /*= _T("")*/, + const PackingInfo * infoUnpacker /*= nullptr*/) { - int pane; + ASSERT(pDirDoc != nullptr); + + if (sReportFile.empty() && pDirDoc->CompareFilesIfFilesAreLarge(nFiles, ifileloc)) + return false; + + String unpackedFileExtension; + if (infoUnpacker && GetOptionsMgr()->GetBool(OPT_PLUGINS_ENABLED)) + { + std::vector filepaths(nFiles); + std::transform(ifileloc, ifileloc + nFiles, filepaths.begin(), + [](auto& file) { return file.filepath; }); + String filteredFilenames = strutils::join(filepaths.begin(), filepaths.end(), _T("|")); + unpackedFileExtension = FileTransform::GetUnpackedFileExtension(filteredFilenames, infoUnpacker); + } FileFilterHelper filterImg, filterBin; filterImg.UseMask(true); filterImg.SetMask(GetOptionsMgr()->GetString(OPT_CMP_IMG_FILEPATTERNS)); filterBin.UseMask(true); filterBin.SetMask(GetOptionsMgr()->GetString(OPT_CMP_BIN_FILEPATTERNS)); - for (pane = 0; pane < nFiles; ++pane) + for (int pane = 0; pane < nFiles; ++pane) { - if (filterImg.includeFile(ifileloc[pane].filepath) && CImgMergeFrame::IsLoadable()) + String filepath = ifileloc[pane].filepath + unpackedFileExtension; + if (filterImg.includeFile(filepath) && CImgMergeFrame::IsLoadable()) return ShowImgMergeDoc(pDirDoc, nFiles, ifileloc, dwFlags, strDesc, sReportFile, infoUnpacker); - else if (filterBin.includeFile(ifileloc[pane].filepath) && CHexMergeView::IsLoadable()) + else if (filterBin.includeFile(filepath) && CHexMergeView::IsLoadable()) return ShowHexMergeDoc(pDirDoc, nFiles, ifileloc, dwFlags, strDesc, sReportFile, infoUnpacker); } - return ShowMergeDoc(pDirDoc, nFiles, ifileloc, dwFlags, strDesc, sReportFile, infoUnpacker); + return ShowTextOrTableMergeDoc({}, pDirDoc, nFiles, ifileloc, dwFlags, strDesc, sReportFile, infoUnpacker); +} + +bool CMainFrame::ShowMergeDoc(UINT nID, CDirDoc* pDirDoc, + int nFiles, const FileLocation ifileloc[], + const DWORD dwFlags[], const String strDesc[], const String& sReportFile /*= _T("")*/, + const PackingInfo* infoUnpacker /*= nullptr*/) +{ + switch (nID) + { + case ID_MERGE_COMPARE_TEXT: + return GetMainFrame()->ShowTextMergeDoc(pDirDoc, nFiles, ifileloc, dwFlags, + strDesc, sReportFile, infoUnpacker); + case ID_MERGE_COMPARE_TABLE: + return GetMainFrame()->ShowTableMergeDoc(pDirDoc, nFiles, ifileloc, dwFlags, + strDesc, sReportFile, infoUnpacker); + case ID_MERGE_COMPARE_HEX: + return GetMainFrame()->ShowHexMergeDoc(pDirDoc, nFiles, ifileloc, dwFlags, + strDesc, sReportFile, infoUnpacker); + case ID_MERGE_COMPARE_IMAGE: + return GetMainFrame()->ShowImgMergeDoc(pDirDoc, nFiles, ifileloc, dwFlags, + strDesc, sReportFile, infoUnpacker); + default: + return GetMainFrame()->ShowAutoMergeDoc(pDirDoc, nFiles, ifileloc, dwFlags, + strDesc, sReportFile, infoUnpacker); + } } std::array GetROFromFlags(int nFiles, const DWORD dwFlags[]) @@ -648,21 +740,21 @@ int GetActivePaneFromFlags(int nFiles, const DWORD dwFlags[]) * @param [in] infoUnpacker Plugin info. * @return success/failure */ -bool CMainFrame::ShowMergeDoc(CDirDoc * pDirDoc, +bool CMainFrame::ShowTextOrTableMergeDoc(std::optional table, CDirDoc * pDirDoc, int nFiles, const FileLocation ifileloc[], - const DWORD dwFlags[], const String strDesc[], const String& sReportFile /*=_T("")*/, - const PackingInfo * infoUnpacker /*= NULL*/) + const DWORD dwFlags[], const String strDesc[], const String& sReportFile /*= _T("")*/, + const PackingInfo * infoUnpacker /*= nullptr*/) { - if (!m_pMenus[MENU_MERGEVIEW]) + if (m_pMenus[MENU_MERGEVIEW] == nullptr) theApp.m_pDiffTemplate->m_hMenuShared = NewMergeViewMenu(); - CMergeDoc * pMergeDoc = GetMergeDocForDiff(theApp.m_pDiffTemplate, pDirDoc, nFiles); + CMergeDoc * pMergeDoc = GetMergeDocForDiff(theApp.m_pDiffTemplate, pDirDoc, nFiles, false); // Make local copies, so we can change encoding if we guess it below FileLocation fileloc[3]; std::copy_n(ifileloc, nFiles, fileloc); - ASSERT(pMergeDoc); // must ASSERT to get an answer to the question below ;-) - if (!pMergeDoc) + ASSERT(pMergeDoc != nullptr); // must ASSERT to get an answer to the question below ;-) + if (pMergeDoc == nullptr) return false; // when does this happen ? // if an unpacker is selected, it must be used during LoadFromFile @@ -681,36 +773,22 @@ bool CMainFrame::ShowMergeDoc(CDirDoc * pDirDoc, { FileLocationGuessEncodings(fileloc[pane], iGuessEncodingType); } - - // TODO (Perry, 2005-12-04) - // Should we do any unification if unicodings are different? - - -#ifndef _UNICODE - // In ANSI (8-bit) build, character loss can occur in merging - // if the two buffers use different encodings - if (pane > 0 && fileloc[pane - 1].encoding.m_codepage != fileloc[pane].encoding.m_codepage) - { - CString msg; - msg.Format(theApp.LoadString(IDS_SUGGEST_IGNORECODEPAGE).c_str(), fileloc[pane - 1].encoding.m_codepage,fileloc[pane].encoding.m_codepage); - int msgflags = MB_YESNO | MB_ICONQUESTION | MB_DONT_ASK_AGAIN; - // Two files with different codepages - // Warn and propose to use the default codepage for both - int userChoice = AfxMessageBox(msg, msgflags); - if (userChoice == IDYES) - { - fileloc[pane - 1].encoding.SetCodepage(ucr::getDefaultCodepage()); - fileloc[pane - 1].encoding.m_bom = false; - fileloc[pane].encoding.SetCodepage(ucr::getDefaultCodepage()); - fileloc[pane].encoding.m_bom = false; - } - } -#endif } + pMergeDoc->SetEnableTableEditing(table); + // Note that OpenDocs() takes care of closing compare window when needed. - if (!pMergeDoc->OpenDocs(nFiles, fileloc, GetROFromFlags(nFiles, dwFlags).data(), strDesc, GetActivePaneFromFlags(nFiles, dwFlags))) + bool bResult = pMergeDoc->OpenDocs(nFiles, fileloc, GetROFromFlags(nFiles, dwFlags).data(), strDesc); + if (bResult) + { + if (CMergeEditFrame *pFrame = pMergeDoc->GetParentFrame()) + if (!pFrame->IsActivated()) + pFrame->InitialUpdateFrame(pMergeDoc, true); + } + else + { return false; + } for (int pane = 0; pane < nFiles; pane++) { @@ -719,7 +797,7 @@ bool CMainFrame::ShowMergeDoc(CDirDoc * pDirDoc, bool bModified = (dwFlags[pane] & FFILEOPEN_MODIFIED) > 0; if (bModified) { - pMergeDoc->m_ptBuf[pane]->SetModified(TRUE); + pMergeDoc->m_ptBuf[pane]->SetModified(true); pMergeDoc->UpdateHeaderPath(pane); } if (dwFlags[pane] & FFILEOPEN_AUTOMERGE) @@ -729,24 +807,46 @@ bool CMainFrame::ShowMergeDoc(CDirDoc * pDirDoc, } } + pMergeDoc->MoveOnLoad(GetActivePaneFromFlags(nFiles, dwFlags)); + if (!sReportFile.empty()) pMergeDoc->GenerateReport(sReportFile); return true; } +bool CMainFrame::ShowTextMergeDoc(CDirDoc* pDirDoc, + int nFiles, const FileLocation ifileloc[], + const DWORD dwFlags[], const String strDesc[], const String& sReportFile /*= _T("")*/, + const PackingInfo* infoUnpacker /*= nullptr*/) +{ + return ShowTextOrTableMergeDoc(false, pDirDoc, nFiles, ifileloc, dwFlags, strDesc, sReportFile, infoUnpacker); +} + +bool CMainFrame::ShowTableMergeDoc(CDirDoc* pDirDoc, + int nFiles, const FileLocation ifileloc[], + const DWORD dwFlags[], const String strDesc[], const String& sReportFile /*= _T("")*/, + const PackingInfo* infoUnpacker /*= nullptr*/) +{ + return ShowTextOrTableMergeDoc(true, pDirDoc, nFiles, ifileloc, dwFlags, strDesc, sReportFile, infoUnpacker); +} + bool CMainFrame::ShowHexMergeDoc(CDirDoc * pDirDoc, int nFiles, const FileLocation fileloc[], - const DWORD dwFlags[], const String strDesc[], const String& sReportFile /*=_T("")*/, - const PackingInfo * infoUnpacker /*= NULL*/) + const DWORD dwFlags[], const String strDesc[], const String& sReportFile /*= _T("")*/, + const PackingInfo * infoUnpacker /*= nullptr*/) { - if (!m_pMenus[MENU_HEXMERGEVIEW]) + if (m_pMenus[MENU_HEXMERGEVIEW] == nullptr) theApp.m_pHexMergeTemplate->m_hMenuShared = NewHexMergeViewMenu(); CHexMergeDoc *pHexMergeDoc = GetMergeDocForDiff(theApp.m_pHexMergeTemplate, pDirDoc, nFiles); - if (!pHexMergeDoc) + if (pHexMergeDoc == nullptr) return false; - if (!pHexMergeDoc->OpenDocs(nFiles, fileloc, GetROFromFlags(nFiles, dwFlags).data(), strDesc, GetActivePaneFromFlags(nFiles, dwFlags))) + pHexMergeDoc->SetUnpacker(infoUnpacker); + + if (!pHexMergeDoc->OpenDocs(nFiles, fileloc, GetROFromFlags(nFiles, dwFlags).data(), strDesc)) return false; + + pHexMergeDoc->MoveOnLoad(GetActivePaneFromFlags(nFiles, dwFlags)); if (!sReportFile.empty()) pHexMergeDoc->GenerateReport(sReportFile); @@ -755,19 +855,19 @@ bool CMainFrame::ShowHexMergeDoc(CDirDoc * pDirDoc, int nFiles, const FileLocati } bool CMainFrame::ShowImgMergeDoc(CDirDoc * pDirDoc, int nFiles, const FileLocation fileloc[], - const DWORD dwFlags[], const String strDesc[], const String& sReportFile /*=_T("")*/, - const PackingInfo * infoUnpacker/* = NULL*/) + const DWORD dwFlags[], const String strDesc[], const String& sReportFile /*= _T("")*/, + const PackingInfo * infoUnpacker /*= nullptr*/) { CImgMergeFrame *pImgMergeFrame = new CImgMergeFrame(); if (!CImgMergeFrame::menu.m_hMenu) CImgMergeFrame::menu.m_hMenu = NewImgMergeViewMenu(); pImgMergeFrame->SetSharedMenu(CImgMergeFrame::menu.m_hMenu); - + pImgMergeFrame->SetUnpacker(infoUnpacker); pImgMergeFrame->SetDirDoc(pDirDoc); pDirDoc->AddMergeDoc(pImgMergeFrame); - if (!pImgMergeFrame->OpenDocs(nFiles, fileloc, GetROFromFlags(nFiles, dwFlags).data(), strDesc, GetActivePaneFromFlags(nFiles, dwFlags), this)) - return ShowMergeDoc(pDirDoc, nFiles, fileloc, dwFlags, strDesc, sReportFile, infoUnpacker); + if (!pImgMergeFrame->OpenDocs(nFiles, fileloc, GetROFromFlags(nFiles, dwFlags).data(), strDesc, this)) + return ShowTextMergeDoc(pDirDoc, nFiles, fileloc, dwFlags, strDesc, sReportFile, infoUnpacker); for (int pane = 0; pane < nFiles; pane++) { @@ -775,19 +875,44 @@ bool CMainFrame::ShowImgMergeDoc(CDirDoc * pDirDoc, int nFiles, const FileLocati pImgMergeFrame->DoAutoMerge(pane); } + pImgMergeFrame->MoveOnLoad(GetActivePaneFromFlags(nFiles, dwFlags)); + if (!sReportFile.empty()) pImgMergeFrame->GenerateReport(sReportFile); return true; } +bool CMainFrame::ShowTextMergeDoc(CDirDoc* pDirDoc, int nBuffers, const String text[], + const String strDesc[], const String& strFileExt) +{ + FileLocation fileloc[3]; + DWORD dwFlags[3] = {}; + CDirDoc* pDirDoc2 = pDirDoc->GetMainView() ? pDirDoc : + static_cast(theApp.m_pDirTemplate->CreateNewDocument()); + for (int nBuffer = 0; nBuffer < nBuffers; ++nBuffer) + { + TempFilePtr wTemp(new TempFile()); + String workFile = wTemp->Create(_T("text_"), strFileExt); + m_tempFiles.push_back(wTemp); + wTemp->Create(_T(""), strFileExt); + UniStdioFile file; + if (file.OpenCreateUtf8(workFile)) + { + file.WriteString(text[nBuffer]); + } + fileloc[nBuffer].setPath(workFile); + } + return ShowTextMergeDoc(pDirDoc2, nBuffers, fileloc, dwFlags, strDesc); +} + /** * @brief Show GNU licence information in notepad (local file) or in Web Browser */ void CMainFrame::OnHelpGnulicense() { const String spath = paths::ConcatPath(env::GetProgPath(), LicenseFile); - theApp.OpenFileOrUrl(spath.c_str(), LicenceUrl); + shell::OpenFileOrUrl(spath.c_str(), LicenceUrl); } /** @@ -804,7 +929,7 @@ void CMainFrame::OnOptions() LANGID lang = static_cast(GetOptionsMgr()->GetInt(OPT_SELECTED_LANGUAGE)); if (lang != theApp.m_pLangDlg->GetLangId()) { - theApp.m_pLangDlg->SetLanguage(lang, TRUE); + theApp.m_pLangDlg->SetLanguage(lang, true); // Update status bar inicator texts theApp.SetIndicators(m_wndStatusBar, 0, 0); @@ -825,6 +950,9 @@ void CMainFrame::OnOptions() String filterPath = GetOptionsMgr()->GetString(OPT_FILTER_USERPATH); theApp.m_pGlobalFileFilter->SetUserFilterPath(filterPath); + CCrystalTextView::RENDERING_MODE nRenderingMode = static_cast(GetOptionsMgr()->GetInt(OPT_RENDERING_MODE)); + CCrystalTextView::SetRenderingModeDefault(nRenderingMode); + theApp.UpdateCodepageModule(); strdiff::SetBreakChars(GetOptionsMgr()->GetString(OPT_BREAK_SEPARATORS).c_str()); @@ -868,9 +996,15 @@ static bool AddToRecentDocs(const PathContext& paths, const unsigned flags[], bo params += _T("/r "); if (!filter.empty()) params += _T("/f \"") + filter + _T("\" "); - return JumpList::AddToRecentDocs(_T(""), params, title, params, 0); -} + Concurrent::CreateTask([params, title](){ + CoInitialize(nullptr); + JumpList::AddToRecentDocs(_T(""), params, title, params, 0); + CoUninitialize(); + return 0; + }); + return true; +} /** * @brief Begin a diff: open dirdoc if it is directories, else open a mergedoc for editing. * @param [in] pszLeft Left-side path. @@ -882,20 +1016,20 @@ static bool AddToRecentDocs(const PathContext& paths, const unsigned flags[], bo * @param [in] prediffer Prediffer plugin name. * @return `true` if opening files and compare succeeded, `false` otherwise. */ -bool CMainFrame::DoFileOpen(const PathContext * pFiles /*=NULL*/, - const DWORD dwFlags[] /*=NULL*/, const String strDesc[] /*=NULL*/, const String& sReportFile /*=T("")*/, bool bRecurse /*= false*/, CDirDoc *pDirDoc/*=NULL*/, - String prediffer /*=_T("")*/, const PackingInfo *infoUnpacker/*=NULL*/) +bool CMainFrame::DoFileOpen(const PathContext * pFiles /*= nullptr*/, + const DWORD dwFlags[] /*= nullptr*/, const String strDesc[] /*= nullptr*/, const String& sReportFile /*= T("")*/, bool bRecurse /*= false*/, CDirDoc *pDirDoc/*= nullptr*/, + String prediffer /*= _T("")*/, const PackingInfo *infoUnpacker /*= nullptr*/) { - if (pDirDoc && !pDirDoc->CloseMergeDocs()) - return FALSE; + if (pDirDoc != nullptr && !pDirDoc->CloseMergeDocs()) + return false; - FileTransform::g_bUnpackerMode = theApp.GetProfileInt(_T("Settings"), _T("UnpackerMode"), PLUGIN_MANUAL); - FileTransform::g_bPredifferMode = theApp.GetProfileInt(_T("Settings"), _T("PredifferMode"), PLUGIN_MANUAL); + FileTransform::g_UnpackerMode = static_cast(GetOptionsMgr()->GetInt(OPT_PLUGINS_UNPACKER_MODE)); + FileTransform::g_PredifferMode = static_cast(GetOptionsMgr()->GetInt(OPT_PLUGINS_PREDIFFER_MODE)); Merge7zFormatMergePluginScope scope(infoUnpacker); PathContext tFiles; - if (pFiles) + if (pFiles != nullptr) tFiles = *pFiles; bool bRO[3] = {0}; if (dwFlags) @@ -909,7 +1043,7 @@ bool CMainFrame::DoFileOpen(const PathContext * pFiles /*=NULL*/, paths::PATH_EXISTENCE pathsType = paths::GetPairComparability(tFiles, IsArchiveFile); if (pathsType == paths::DOES_NOT_EXIST) { - if (!m_pMenus[MENU_OPENVIEW]) + if (m_pMenus[MENU_OPENVIEW] == nullptr) theApp.m_pOpenTemplate->m_hMenuShared = NewOpenViewMenu(); COpenDoc *pOpenDoc = static_cast(theApp.m_pOpenTemplate->CreateNewDocument()); if (dwFlags) @@ -922,9 +1056,9 @@ bool CMainFrame::DoFileOpen(const PathContext * pFiles /*=NULL*/, pOpenDoc->m_bRecurse = bRecurse; if (infoUnpacker) pOpenDoc->m_infoHandler = *infoUnpacker; - CFrameWnd *pFrame = theApp.m_pOpenTemplate->CreateNewFrame(pOpenDoc, NULL); + CFrameWnd *pFrame = theApp.m_pOpenTemplate->CreateNewFrame(pOpenDoc, nullptr); theApp.m_pOpenTemplate->InitialUpdateFrame(pFrame, pOpenDoc); - return TRUE; + return true; } else { @@ -951,7 +1085,7 @@ bool CMainFrame::DoFileOpen(const PathContext * pFiles /*=NULL*/, } } - CTempPathContext *pTempPathContext = NULL; + CTempPathContext *pTempPathContext = nullptr; if (pathsType == paths::IS_EXISTING_DIR) { DecompressResult res= DecompressArchive(m_hWnd, tFiles); @@ -965,14 +1099,14 @@ bool CMainFrame::DoFileOpen(const PathContext * pFiles /*=NULL*/, // Determine if we want a new dirview open, now that we know if it was // an archive. Don't open a new dirview if we are comparing files. - if (!pDirDoc) + if (pDirDoc == nullptr) { if (pathsType == paths::IS_EXISTING_DIR) { CDirDoc::m_nDirsTemp = tFiles.GetSize(); - if (!m_pMenus[MENU_DIRVIEW]) + if (m_pMenus[MENU_DIRVIEW] == nullptr) theApp.m_pDirTemplate->m_hMenuShared = NewDirViewMenu(); - pDirDoc = static_cast(theApp.m_pDirTemplate->OpenDocumentFile(NULL)); + pDirDoc = static_cast(theApp.m_pDirTemplate->OpenDocumentFile(nullptr)); } else { @@ -983,7 +1117,7 @@ bool CMainFrame::DoFileOpen(const PathContext * pFiles /*=NULL*/, // open the diff if (pathsType == paths::IS_EXISTING_DIR) { - if (pDirDoc) + if (pDirDoc != nullptr) { // Anything that can go wrong inside InitCompare() will yield an // exception. There is no point in checking return value. @@ -991,7 +1125,7 @@ bool CMainFrame::DoFileOpen(const PathContext * pFiles /*=NULL*/, pDirDoc->SetReportFile(sReportFile); pDirDoc->SetDescriptions(strDesc); - pDirDoc->SetTitle(NULL); + pDirDoc->SetTitle(nullptr); for (int nIndex = 0; nIndex < tFiles.GetSize(); nIndex++) pDirDoc->SetReadOnly(nIndex, bRO[nIndex]); @@ -1015,13 +1149,24 @@ bool CMainFrame::DoFileOpen(const PathContext * pFiles /*=NULL*/, infoUnpacker); } - if (pFiles && (!dwFlags || !(dwFlags[0] & FFILEOPEN_NOMRU))) + if (pFiles != nullptr && (!dwFlags || !(dwFlags[0] & FFILEOPEN_NOMRU))) { String filter = GetOptionsMgr()->GetString(OPT_FILEFILTER_CURRENT); AddToRecentDocs(*pFiles, (unsigned *)dwFlags, bRecurse, filter); } - return TRUE; + return true; +} + +bool CMainFrame::DoFileOpen(UINT nID, const PathContext* pFiles /*= nullptr*/, + const DWORD dwFlags[] /*= nullptr*/, const String strDesc[] /*= nullptr*/) +{ + CDirDoc* pDirDoc = static_cast(theApp.m_pDirTemplate->CreateNewDocument()); + FileLocation fileloc[3]; + for (int pane = 0; pane < pFiles->GetSize(); pane++) + fileloc[pane].setPath((*pFiles)[pane]); + return ShowMergeDoc(nID, pDirDoc, pFiles->GetSize(), fileloc, + dwFlags, strDesc); } void CMainFrame::UpdateFont(FRAMETYPE frame) @@ -1030,10 +1175,10 @@ void CMainFrame::UpdateFont(FRAMETYPE frame) { for (auto pDoc : GetAllDirDocs()) { - if (pDoc) + if (pDoc != nullptr) { CDirView *pView = pDoc->GetMainView(); - if (pView) + if (pView != nullptr) pView->SetFont(m_lfDir); } } @@ -1043,7 +1188,7 @@ void CMainFrame::UpdateFont(FRAMETYPE frame) for (auto pDoc : GetAllMergeDocs()) { CMergeDoc *pMergeDoc = dynamic_cast(pDoc); - if (pMergeDoc) + if (pMergeDoc != nullptr) for (auto& pView: pMergeDoc->GetViewList()) pView->SetFont(m_lfDiff); } @@ -1063,7 +1208,7 @@ void CMainFrame::OnViewSelectfont() { FRAMETYPE frame = GetFrameType(GetActiveFrame()); CHOOSEFONT cf = { sizeof CHOOSEFONT }; - LOGFONT *lf = NULL; + LOGFONT *lf = nullptr; cf.Flags = CF_INITTOLOGFONTSTRUCT|CF_FORCEFONTEXIST|CF_SCREENFONTS; if (frame == FRAME_FILE) cf.Flags |= CF_FIXEDPITCHONLY; // Only fixed-width fonts for merge view @@ -1123,6 +1268,8 @@ void CMainFrame::UpdateResources() pDoc->UpdateResources(); for (auto pDoc : GetAllOpenDocs()) pDoc->UpdateResources(); + for (auto pFrame: GetAllImgMergeFrames()) + pFrame->UpdateResources(); } /** @@ -1156,7 +1303,7 @@ void CMainFrame::ActivateFrame(int nCmdShow) m_bFirstTime = false; - WINDOWPLACEMENT wp; + WINDOWPLACEMENT wp = {}; wp.length = sizeof(WINDOWPLACEMENT); GetWindowPlacement(&wp); wp.rcNormalPosition.left=theApp.GetProfileInt(_T("Settings"), _T("MainLeft"),0); @@ -1214,7 +1361,7 @@ void CMainFrame::OnClose() GetOptionsMgr()->SaveOption(OPT_FILEFILTER_CURRENT, filter); // save main window position - WINDOWPLACEMENT wp; + WINDOWPLACEMENT wp = {}; wp.length = sizeof(WINDOWPLACEMENT); GetWindowPlacement(&wp); theApp.WriteProfileInt(_T("Settings"), _T("MainLeft"),wp.rcNormalPosition.left); @@ -1223,17 +1370,10 @@ void CMainFrame::OnClose() theApp.WriteProfileInt(_T("Settings"), _T("MainBottom"),wp.rcNormalPosition.bottom); theApp.WriteProfileInt(_T("Settings"), _T("MainMax"), (wp.showCmd == SW_MAXIMIZE)); - // Close Non-Document/View frame with confirmation - CMDIChildWnd *pChild = static_cast(CWnd::FromHandle(m_hWndMDIClient)->GetWindow(GW_CHILD)); - while (pChild) + for (auto pFrame: GetAllImgMergeFrames()) { - CMDIChildWnd *pNextChild = static_cast(pChild->GetWindow(GW_HWNDNEXT)); - if (GetFrameType(pChild) == FRAME_IMGFILE) - { - if (!static_cast(pChild)->CloseNow()) - return; - } - pChild = pNextChild; + if (!pFrame->CloseNow()) + return; } CMDIFrameWnd::OnClose(); @@ -1268,7 +1408,7 @@ void CMainFrame::ApplyDiffOptions() // Re-read MergeDoc settings (also updates view settings) // and rescan using new options pMergeDoc->RefreshOptions(); - pMergeDoc->FlushAndRescan(TRUE); + pMergeDoc->FlushAndRescan(true); } } @@ -1296,17 +1436,32 @@ HexMergeDocList &CMainFrame::GetAllHexMergeDocs() return static_cast(GetDocList(theApp.m_pHexMergeTemplate)); } +std::list CMainFrame::GetAllImgMergeFrames() +{ + std::list list; + // Close Non-Document/View frame with confirmation + CMDIChildWnd *pChild = static_cast(CWnd::FromHandle(m_hWndMDIClient)->GetWindow(GW_CHILD)); + while (pChild != nullptr) + { + CMDIChildWnd *pNextChild = static_cast(pChild->GetWindow(GW_HWNDNEXT)); + if (GetFrameType(pChild) == FRAME_IMGFILE) + list.push_back(static_cast(pChild)); + pChild = pNextChild; + } + return list; +} + /** * @brief Obtain a merge doc to display a difference in files. * @return Pointer to CMergeDoc to use. */ template -DocClass * GetMergeDocForDiff(CMultiDocTemplate *pTemplate, CDirDoc *pDirDoc, int nFiles) +DocClass * GetMergeDocForDiff(CMultiDocTemplate *pTemplate, CDirDoc *pDirDoc, int nFiles, bool bMakeVisible) { // Create a new merge doc DocClass::m_nBuffersTemp = nFiles; - DocClass *pMergeDoc = static_cast(pTemplate->OpenDocumentFile(NULL)); - if (pMergeDoc) + DocClass *pMergeDoc = static_cast(pTemplate->OpenDocumentFile(nullptr, bMakeVisible)); + if (pMergeDoc != nullptr) { pDirDoc->AddMergeDoc(pMergeDoc); pMergeDoc->SetDirDoc(pDirDoc); @@ -1338,8 +1493,10 @@ void CMainFrame::OnDropFiles(const std::vector& dropped_files) PathContext tFiles(dropped_files); const size_t fileCount = tFiles.GetSize(); - // If Ctrl pressed, do recursive compare - bool recurse = !!::GetAsyncKeyState(VK_CONTROL) || GetOptionsMgr()->GetBool(OPT_CMP_INCLUDE_SUBDIRS); + bool recurse = GetOptionsMgr()->GetBool(OPT_CMP_INCLUDE_SUBDIRS); + // Do a reverse comparison with the current 'Include Subfolders' settings when pressing Control key + if (::GetAsyncKeyState(VK_CONTROL) & 0x8000) + recurse = !recurse; // If user has pressed with one file selected, // assume it is an archive and set filenames to same @@ -1364,7 +1521,7 @@ void CMainFrame::OnDropFiles(const std::vector& dropped_files) } } - DoFileOpen(&tFiles, dwFlags, NULL, _T(""), recurse); + DoFileOpen(&tFiles, dwFlags, nullptr, _T(""), recurse); } void CMainFrame::OnPluginUnpackMode(UINT nID ) @@ -1372,13 +1529,13 @@ void CMainFrame::OnPluginUnpackMode(UINT nID ) switch (nID) { case ID_UNPACK_MANUAL: - FileTransform::g_bUnpackerMode = PLUGIN_MANUAL; + FileTransform::g_UnpackerMode = PLUGIN_MODE::PLUGIN_MANUAL; break; case ID_UNPACK_AUTO: - FileTransform::g_bUnpackerMode = PLUGIN_AUTO; + FileTransform::g_UnpackerMode = PLUGIN_MODE::PLUGIN_AUTO; break; } - theApp.WriteProfileInt(_T("Settings"), _T("UnpackerMode"), FileTransform::g_bUnpackerMode); + GetOptionsMgr()->SaveOption(OPT_PLUGINS_UNPACKER_MODE, static_cast(FileTransform::g_UnpackerMode)); } void CMainFrame::OnUpdatePluginUnpackMode(CCmdUI* pCmdUI) @@ -1386,27 +1543,27 @@ void CMainFrame::OnUpdatePluginUnpackMode(CCmdUI* pCmdUI) pCmdUI->Enable(GetOptionsMgr()->GetBool(OPT_PLUGINS_ENABLED)); if (pCmdUI->m_nID == ID_UNPACK_MANUAL) - pCmdUI->SetRadio(PLUGIN_MANUAL == FileTransform::g_bUnpackerMode); + pCmdUI->SetRadio(PLUGIN_MODE::PLUGIN_MANUAL == FileTransform::g_UnpackerMode); if (pCmdUI->m_nID == ID_UNPACK_AUTO) - pCmdUI->SetRadio(PLUGIN_AUTO == FileTransform::g_bUnpackerMode); + pCmdUI->SetRadio(PLUGIN_MODE::PLUGIN_AUTO == FileTransform::g_UnpackerMode); } void CMainFrame::OnPluginPrediffMode(UINT nID ) { switch (nID) { case ID_PREDIFFER_MANUAL: - FileTransform::g_bPredifferMode = PLUGIN_MANUAL; + FileTransform::g_PredifferMode = PLUGIN_MODE::PLUGIN_MANUAL; break; case ID_PREDIFFER_AUTO: - FileTransform::g_bPredifferMode = PLUGIN_AUTO; + FileTransform::g_PredifferMode = PLUGIN_MODE::PLUGIN_AUTO; break; } PrediffingInfo infoPrediffer; for (auto pMergeDoc : GetAllMergeDocs()) pMergeDoc->SetPrediffer(&infoPrediffer); for (auto pDirDoc : GetAllDirDocs()) - pDirDoc->GetPluginManager().SetPrediffSettingAll(FileTransform::g_bPredifferMode); - theApp.WriteProfileInt(_T("Settings"), _T("PredifferMode"), FileTransform::g_bPredifferMode); + pDirDoc->GetPluginManager().SetPrediffSettingAll(FileTransform::g_PredifferMode); + GetOptionsMgr()->SaveOption(OPT_PLUGINS_PREDIFFER_MODE, static_cast(FileTransform::g_PredifferMode)); } void CMainFrame::OnUpdatePluginPrediffMode(CCmdUI* pCmdUI) @@ -1414,9 +1571,9 @@ void CMainFrame::OnUpdatePluginPrediffMode(CCmdUI* pCmdUI) pCmdUI->Enable(GetOptionsMgr()->GetBool(OPT_PLUGINS_ENABLED)); if (pCmdUI->m_nID == ID_PREDIFFER_MANUAL) - pCmdUI->SetRadio(PLUGIN_MANUAL == FileTransform::g_bPredifferMode); + pCmdUI->SetRadio(PLUGIN_MODE::PLUGIN_MANUAL == FileTransform::g_PredifferMode); if (pCmdUI->m_nID == ID_PREDIFFER_AUTO) - pCmdUI->SetRadio(PLUGIN_AUTO == FileTransform::g_bPredifferMode); + pCmdUI->SetRadio(PLUGIN_MODE::PLUGIN_AUTO == FileTransform::g_PredifferMode); } /** * @brief Called when "Reload Plugins" item is updated @@ -1434,7 +1591,7 @@ void CMainFrame::OnReloadPlugins() // update the editor scripts submenu HMENU scriptsSubmenu = GetScriptsSubmenu(m_hMenuDefault); - if (scriptsSubmenu != NULL) + if (scriptsSubmenu != nullptr) CMergeEditView::createScriptsSubmenu(scriptsSubmenu); UpdatePrediffersMenu(); } @@ -1444,15 +1601,15 @@ CMergeEditView * CMainFrame::GetActiveMergeEditView() { // NB: GetActiveDocument does not return the Merge Doc // even when the merge edit view is in front - // NB: CChildFrame::GetActiveView returns NULL when location view active + // NB: CMergeEditFrame::GetActiveView returns `nullptr` when location view active // So we have this rather complicated logic to try to get a merge edit view // We look at the front child window, which should be a frame - // and we can get a MergeEditView from it, if it is a CChildFrame + // and we can get a MergeEditView from it, if it is a CMergeEditFrame // (DirViews use a different frame type) - CChildFrame * pFrame = dynamic_cast(GetActiveFrame()); - if (!pFrame) return 0; + CMergeEditFrame * pFrame = dynamic_cast(GetActiveFrame()); + if (pFrame == nullptr) return nullptr; // Try to get the active MergeEditView (ie, left or right) - if (pFrame->GetActiveView() && pFrame->GetActiveView()->IsKindOf(RUNTIME_CLASS(CMergeEditView))) + if (pFrame->GetActiveView() != nullptr && pFrame->GetActiveView()->IsKindOf(RUNTIME_CLASS(CMergeEditView))) { return dynamic_cast(pFrame->GetActiveView()); } @@ -1462,17 +1619,17 @@ CMergeEditView * CMainFrame::GetActiveMergeEditView() void CMainFrame::UpdatePrediffersMenu() { CMenu* menu = GetMenu(); - if (menu == NULL) + if (menu == nullptr) { return; } HMENU hMainMenu = menu->m_hMenu; HMENU prediffersSubmenu = GetPrediffersSubmenu(hMainMenu); - if (prediffersSubmenu != NULL) + if (prediffersSubmenu != nullptr) { CMergeEditView * pEditView = GetActiveMergeEditView(); - if (pEditView) + if (pEditView != nullptr) pEditView->createPrediffersSubmenu(prediffersSubmenu); else { @@ -1480,7 +1637,7 @@ void CMainFrame::UpdatePrediffersMenu() int i = GetMenuItemCount(prediffersSubmenu); while (i --) ::DeleteMenu(prediffersSubmenu, 0, MF_BYPOSITION); - ::AppendMenu(prediffersSubmenu, MF_SEPARATOR, 0, NULL); + ::AppendMenu(prediffersSubmenu, MF_SEPARATOR, 0, nullptr); } } } @@ -1496,7 +1653,7 @@ void CMainFrame::OnSaveConfigData() if (configLog.WriteLogFile(sError)) { String sFileName = configLog.GetFileName(); - theApp.OpenFileToExternalEditor(sFileName); + CMergeApp::OpenFileToExternalEditor(sFileName); } else { @@ -1516,7 +1673,7 @@ void CMainFrame::OnSaveConfigData() * @sa CMergeDoc::OpenDocs() * @sa CMergeDoc::TrySaveAs() */ -void CMainFrame::FileNew(int nPanes) +void CMainFrame::FileNew(int nPanes, FRAMETYPE frameType, bool table) { CDirDoc *pDirDoc = static_cast(theApp.m_pDirTemplate->CreateNewDocument()); @@ -1531,7 +1688,6 @@ void CMainFrame::FileNew(int nPanes) strDesc[1] = _("Untitled right"); fileloc[0].encoding.SetCodepage(ucr::getDefaultCodepage()); fileloc[1].encoding.SetCodepage(ucr::getDefaultCodepage()); - ShowMergeDoc(pDirDoc, 2, fileloc, dwFlags, strDesc); } else { @@ -1541,8 +1697,15 @@ void CMainFrame::FileNew(int nPanes) fileloc[0].encoding.SetCodepage(ucr::getDefaultCodepage()); fileloc[1].encoding.SetCodepage(ucr::getDefaultCodepage()); fileloc[2].encoding.SetCodepage(ucr::getDefaultCodepage()); - ShowMergeDoc(pDirDoc, 3, fileloc, dwFlags, strDesc); } + UINT nID = ID_MERGE_COMPARE_TEXT; + switch (frameType) + { + case FRAME_FILE: nID = !table ? ID_MERGE_COMPARE_TEXT : ID_MERGE_COMPARE_TABLE; break; + case FRAME_HEXFILE: nID = ID_MERGE_COMPARE_HEX; break; + case FRAME_IMGFILE: nID = ID_MERGE_COMPARE_IMAGE; break; + } + ShowMergeDoc(nID, pDirDoc, nPanes, fileloc, dwFlags, strDesc); } /** @@ -1555,14 +1718,10 @@ void CMainFrame::FileNew(int nPanes) * @sa CMergeDoc::OpenDocs() * @sa CMergeDoc::TrySaveAs() */ +template void CMainFrame::OnFileNew() { - FileNew(2); -} - -void CMainFrame::OnFileNew3() -{ - FileNew(3); + FileNew(nFiles, frameType, table); } /** @@ -1573,20 +1732,21 @@ void CMainFrame::OnToolsFilters() String title = _("Filters"); CPropertySheet sht(title.c_str()); LineFiltersDlg lineFiltersDlg; + SubstitutionFiltersDlg substitutionFiltersDlg; FileFiltersDlg fileFiltersDlg; - vector fileFilters; std::unique_ptr lineFilters(new LineFiltersList()); + std::unique_ptr SubstitutionFilters(new SubstitutionFiltersList()); String selectedFilter; const String origFilter = theApp.m_pGlobalFileFilter->GetFilterNameOrMask(); sht.AddPage(&fileFiltersDlg); sht.AddPage(&lineFiltersDlg); + sht.AddPage(&substitutionFiltersDlg); sht.m_psh.dwFlags |= PSH_NOAPPLYNOW; // Hide 'Apply' button since we don't need it // Make sure all filters are up-to-date theApp.m_pGlobalFileFilter->ReloadUpdatedFilters(); - theApp.m_pGlobalFileFilter->GetFileFilters(&fileFilters, selectedFilter); - fileFiltersDlg.SetFilterArray(&fileFilters); + fileFiltersDlg.SetFilterArray(theApp.m_pGlobalFileFilter->GetFileFilters(selectedFilter)); fileFiltersDlg.SetSelected(selectedFilter); const bool lineFiltersEnabledOrig = GetOptionsMgr()->GetBool(OPT_LINEFILTER_ENABLED); lineFiltersDlg.m_bIgnoreRegExp = lineFiltersEnabledOrig; @@ -1594,6 +1754,11 @@ void CMainFrame::OnToolsFilters() lineFilters->CloneFrom(theApp.m_pLineFilters.get()); lineFiltersDlg.SetList(lineFilters.get()); + SubstitutionFilters->CloneFrom(theApp.m_pSubstitutionFiltersList.get()); + substitutionFiltersDlg.SetList(SubstitutionFilters.get()); + + sht.SetActivePage(AfxGetApp()->GetProfileInt(_T("Settings"), _T("FilterStartPage"), 0)); + if (sht.DoModal() == IDOK) { String strNone = _(""); @@ -1625,8 +1790,12 @@ void CMainFrame::OnToolsFilters() FRAMETYPE frame = GetFrameType(pFrame); if (frame == FRAME_FILE) { - if (lineFiltersEnabledOrig != linefiltersEnabled || - !theApp.m_pLineFilters->Compare(lineFilters.get())) + if + ( + linefiltersEnabled != lineFiltersEnabledOrig + || !lineFilters->Compare(theApp.m_pLineFilters.get()) + || !SubstitutionFilters->Compare(theApp.m_pSubstitutionFiltersList.get()) + ) { bFileCompareRescan = true; } @@ -1647,10 +1816,13 @@ void CMainFrame::OnToolsFilters() theApp.m_pLineFilters->CloneFrom(lineFilters.get()); theApp.m_pLineFilters->SaveFilters(); + theApp.m_pSubstitutionFiltersList->CloneFrom(SubstitutionFilters.get()); + theApp.m_pSubstitutionFiltersList->SaveFilters(); + if (bFileCompareRescan) { for (auto pMergeDoc : GetAllMergeDocs()) - pMergeDoc->FlushAndRescan(TRUE); + pMergeDoc->FlushAndRescan(true); } else if (bFolderCompareRescan) { @@ -1683,15 +1855,24 @@ BOOL CMainFrame::PreTranslateMessage(MSG* pMsg) { if (theApp.m_bEscShutdown && m_wndTabBar.GetItemCount() <= 1) { - AfxGetMainWnd()->PostMessage(WM_COMMAND, ID_APP_EXIT); + AfxGetMainWnd()->SendMessage(WM_COMMAND, ID_APP_EXIT); return TRUE; } - else if (GetOptionsMgr()->GetBool(OPT_CLOSE_WITH_ESC) && m_wndTabBar.GetItemCount() == 0) + else if (GetOptionsMgr()->GetInt(OPT_CLOSE_WITH_ESC) == 1 && m_wndTabBar.GetItemCount() == 0) { AfxGetMainWnd()->PostMessage(WM_COMMAND, ID_APP_EXIT); return FALSE; } } + + if (WM_KEYDOWN == pMsg->message && VK_TAB == pMsg->wParam && GetAsyncKeyState(VK_CONTROL) < 0 && m_arrChild.GetSize() > 1) + { + CWindowsManagerDialog* pDlg = new CWindowsManagerDialog; + pDlg->Create(CWindowsManagerDialog::IDD, this); + pDlg->ShowWindow(SW_SHOW); + return TRUE; + } + return CMDIFrameWnd::PreTranslateMessage(pMsg); } @@ -1743,7 +1924,7 @@ void CMainFrame::OnResizePanes() GetOptionsMgr()->SaveOption(OPT_RESIZE_PANES, bResize); // TODO: Introduce a common merge frame superclass? CFrameWnd *pActiveFrame = GetActiveFrame(); - if (CChildFrame *pFrame = DYNAMIC_DOWNCAST(CChildFrame, pActiveFrame)) + if (CMergeEditFrame *pFrame = DYNAMIC_DOWNCAST(CMergeEditFrame, pActiveFrame)) { pFrame->UpdateAutoPaneResize(); if (bResize) @@ -1774,7 +1955,7 @@ void CMainFrame::OnFileOpenProject() // store this as the new project path GetOptionsMgr()->SaveOption(OPT_PROJECTS_PATH, strProjectPath); - theApp.LoadAndOpenProjectFile(sFilepath.c_str()); + theApp.LoadAndOpenProjectFile(sFilepath); } /** @@ -1801,15 +1982,8 @@ LRESULT CMainFrame::OnCopyData(WPARAM wParam, LPARAM lParam) LRESULT CMainFrame::OnUser1(WPARAM wParam, LPARAM lParam) { - CFrameWnd * pFrame = GetActiveFrame(); - if (pFrame) - { - IMergeDoc *pMergeDoc = dynamic_cast(pFrame->GetActiveDocument()); - if (!pMergeDoc) - pMergeDoc = dynamic_cast(pFrame); - if (pMergeDoc) - pMergeDoc->CheckFileChanged(); - } + if (IMergeDoc *pMergeDoc = GetActiveIMergeDoc()) + pMergeDoc->CheckFileChanged(); return 0; } @@ -1821,10 +1995,10 @@ LRESULT CMainFrame::OnUser1(WPARAM wParam, LPARAM lParam) void CMainFrame::OnWindowCloseAll() { CMDIChildWnd *pChild = MDIGetActive(); - while (pChild) + while (pChild != nullptr) { CDocument* pDoc; - if ((pDoc = pChild->GetActiveDocument()) != NULL) + if ((pDoc = pChild->GetActiveDocument()) != nullptr) { if (!pDoc->SaveModified()) return; @@ -1849,15 +2023,7 @@ void CMainFrame::OnWindowCloseAll() */ void CMainFrame::OnUpdateWindowCloseAll(CCmdUI* pCmdUI) { - const MergeDocList &mergedocs = GetAllMergeDocs(); - if (!mergedocs.IsEmpty()) - { - pCmdUI->Enable(TRUE); - return; - } - - const DirDocList &dirdocs = GetAllDirDocs(); - pCmdUI->Enable(!dirdocs.IsEmpty()); + pCmdUI->Enable(MDIGetActive() != nullptr); } /** @@ -1879,7 +2045,7 @@ CMainFrame * GetMainFrame() */ void CMainFrame::OnSaveProject() { - if (!m_pMenus[MENU_OPENVIEW]) + if (m_pMenus[MENU_OPENVIEW] == nullptr) theApp.m_pOpenTemplate->m_hMenuShared = NewOpenViewMenu(); COpenDoc *pOpenDoc = static_cast(theApp.m_pOpenTemplate->CreateNewDocument()); @@ -1891,7 +2057,7 @@ void CMainFrame::OnSaveProject() { CMergeDoc * pMergeDoc = static_cast(pFrame->GetActiveDocument()); pOpenDoc->m_files = pMergeDoc->m_filePaths; - for (size_t pane = 0; pane < pOpenDoc->m_files.size(); ++pane) + for (int pane = 0; pane < pOpenDoc->m_files.GetSize(); ++pane) pOpenDoc->m_dwFlags[pane] = FFILEOPEN_PROJECT | (pMergeDoc->m_ptBuf[pane]->GetReadOnly() ? FFILEOPEN_PROJECT : 0); pOpenDoc->m_bRecurse = GetOptionsMgr()->GetBool(OPT_CMP_INCLUDE_SUBDIRS); pOpenDoc->m_strExt = theApp.m_pGlobalFileFilter->GetFilterNameOrMask(); @@ -1912,7 +2078,7 @@ void CMainFrame::OnSaveProject() pOpenDoc->m_strExt = static_cast(ctxt.m_piFilterGlobal)->GetFilterNameOrMask(); } - CFrameWnd *pOpenFrame = theApp.m_pOpenTemplate->CreateNewFrame(pOpenDoc, NULL); + CFrameWnd *pOpenFrame = theApp.m_pOpenTemplate->CreateNewFrame(pOpenDoc, nullptr); theApp.m_pOpenTemplate->InitialUpdateFrame(pOpenFrame, pOpenDoc); } @@ -1923,7 +2089,7 @@ void CMainFrame::StartFlashing() { CWnd * activeWindow = GetActiveWindow(); if (activeWindow != this) - FlashWindowEx(FLASHW_ALL | FLASHW_TIMERNOFG, 0, 0); + FlashWindowEx(FLASHW_ALL | FLASHW_TIMERNOFG, 3, 0); } #if _MFC_VER > 0x0600 @@ -1938,15 +2104,8 @@ void CMainFrame::OnActivateApp(BOOL bActive, HTASK hTask) CMDIFrameWnd::OnActivateApp(bActive, hTask); #endif - CFrameWnd * pFrame = GetActiveFrame(); - if (pFrame) - { - IMergeDoc *pMergeDoc = dynamic_cast(pFrame->GetActiveDocument()); - if (!pMergeDoc) - pMergeDoc = dynamic_cast(pFrame); - if (pMergeDoc) - PostMessage(WM_USER+1); - } + if (IMergeDoc *pMergeDoc = GetActiveIMergeDoc()) + PostMessage(WM_USER+1); } BOOL CMainFrame::CreateToolbar() @@ -1957,7 +2116,8 @@ BOOL CMainFrame::CreateToolbar() return FALSE; } - if (!m_wndReBar.Create(this)) + if (!m_wndReBar.Create(this, RBS_BANDBORDERS, + WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | CBRS_ALIGN_TOP)) { return FALSE; } @@ -1974,11 +2134,14 @@ BOOL CMainFrame::CreateToolbar() LoadToolbarImages(); UINT nID, nStyle; - int iImage; - int index = m_wndToolBar.GetToolBarCtrl().CommandToIndex(ID_OPTIONS); - m_wndToolBar.GetButtonInfo(index, nID, nStyle, iImage); - nStyle |= TBSTYLE_DROPDOWN; - m_wndToolBar.SetButtonInfo(index, nID, nStyle, iImage); + for (auto cmd : { ID_OPTIONS, ID_FILE_NEW, ID_FILE_OPEN, ID_FILE_SAVE }) + { + int iImage; + int index = m_wndToolBar.GetToolBarCtrl().CommandToIndex(cmd); + m_wndToolBar.GetButtonInfo(index, nID, nStyle, iImage); + nStyle |= TBSTYLE_DROPDOWN; + m_wndToolBar.SetButtonInfo(index, nID, nStyle, iImage); + } if (!GetOptionsMgr()->GetBool(OPT_SHOW_TOOLBAR)) { @@ -1991,28 +2154,28 @@ BOOL CMainFrame::CreateToolbar() /** @brief Load toolbar images from the resource. */ void CMainFrame::LoadToolbarImages() { - const int toolbarSize = 16 << GetOptionsMgr()->GetInt(OPT_TOOLBAR_SIZE); + const int toolbarNewImgSize = MulDiv(16, GetSystemMetrics(SM_CXSMICON), 16) * (1 + GetOptionsMgr()->GetInt(OPT_TOOLBAR_SIZE)); + const int toolbarOrgImgSize = toolbarNewImgSize <= 20 ? 16 : 32; CToolBarCtrl& BarCtrl = m_wndToolBar.GetToolBarCtrl(); - m_ToolbarImages[TOOLBAR_IMAGES_ENABLED].DeleteImageList(); - m_ToolbarImages[TOOLBAR_IMAGES_DISABLED].DeleteImageList(); + m_ToolbarImages[TOOLBAR_IMAGES_ENABLED].Detach(); + m_ToolbarImages[TOOLBAR_IMAGES_DISABLED].Detach(); CSize sizeButton(0, 0); - LoadToolbarImageList(toolbarSize, - toolbarSize <= 16 ? IDB_TOOLBAR_ENABLED : IDB_TOOLBAR_ENABLED32, - toolbarSize <= 16 ? IDB_TOOLBAR_ENABLED_MASK : IDB_TOOLBAR_ENABLED_MASK32, + LoadToolbarImageList(toolbarOrgImgSize, toolbarNewImgSize, + toolbarOrgImgSize <= 16 ? IDB_TOOLBAR_ENABLED : IDB_TOOLBAR_ENABLED32, false, m_ToolbarImages[TOOLBAR_IMAGES_ENABLED]); - LoadToolbarImageList(toolbarSize, - toolbarSize <= 16 ? IDB_TOOLBAR_ENABLED : IDB_TOOLBAR_ENABLED32, - toolbarSize <= 16 ? IDB_TOOLBAR_ENABLED_MASK : IDB_TOOLBAR_ENABLED_MASK32, + LoadToolbarImageList(toolbarOrgImgSize, toolbarNewImgSize, + toolbarOrgImgSize <= 16 ? IDB_TOOLBAR_ENABLED : IDB_TOOLBAR_ENABLED32, true, m_ToolbarImages[TOOLBAR_IMAGES_DISABLED]); - sizeButton = CSize(toolbarSize + 8, toolbarSize + 8); + + sizeButton = CSize(toolbarNewImgSize + 8, toolbarNewImgSize + 8); BarCtrl.SetButtonSize(sizeButton); - BarCtrl.SetImageList(&m_ToolbarImages[TOOLBAR_IMAGES_ENABLED]); - BarCtrl.SetDisabledImageList(&m_ToolbarImages[TOOLBAR_IMAGES_DISABLED]); - m_ToolbarImages[TOOLBAR_IMAGES_ENABLED].Detach(); - m_ToolbarImages[TOOLBAR_IMAGES_DISABLED].Detach(); + if (CImageList *pImgList = BarCtrl.SetImageList(&m_ToolbarImages[TOOLBAR_IMAGES_ENABLED])) + pImgList->DeleteImageList(); + if (CImageList *pImgList = BarCtrl.SetDisabledImageList(&m_ToolbarImages[TOOLBAR_IMAGES_DISABLED])) + pImgList->DeleteImageList(); // resize the rebar. REBARBANDINFO rbbi = { sizeof REBARBANDINFO }; @@ -2023,29 +2186,27 @@ void CMainFrame::LoadToolbarImages() /** - * @brief Load a transparent 24-bit color image list. + * @brief Load a transparent 32-bit color image list. */ -static void LoadHiColImageList(UINT nIDResource, UINT nIDResourceMask, int nWidth, int nHeight, int nCount, bool bGrayscale, CImageList& ImgList) +static void LoadHiColImageList(UINT nIDResource, int nWidth, int nHeight, int nNewWidth, int nNewHeight, int nCount, bool bGrayscale, CImageList& ImgList) { - CBitmap bm, bmMask; - bm.Attach(LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(nIDResource), IMAGE_BITMAP, nWidth * nCount, nHeight, LR_DEFAULTCOLOR)); - bmMask.Attach(LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(nIDResourceMask), IMAGE_BITMAP, nWidth * nCount, nHeight, LR_MONOCHROME)); - if (bGrayscale) - GrayScale(&bm); - VERIFY(ImgList.Create(nWidth, nHeight, ILC_COLORDDB|ILC_MASK, nCount, 0)); - int nIndex = ImgList.Add(&bm, &bmMask); + CBitmap bm; + bm.Attach(LoadBitmapAndConvertTo32bit(AfxGetInstanceHandle(), nIDResource, nNewWidth * nCount, nNewHeight, bGrayscale, RGB(0xff, 0, 0xff))); + + VERIFY(ImgList.Create(nNewWidth, nNewHeight, ILC_COLOR32, nCount, 0)); + int nIndex = ImgList.Add(&bm, nullptr); ASSERT(-1 != nIndex); } /** * @brief Load toolbar image list. */ -static void LoadToolbarImageList(int imageWidth, UINT nIDResource, UINT nIDResourceMask, bool bGrayscale, - CImageList& ImgList) +static void LoadToolbarImageList(int orgImageWidth, int newImageWidth, UINT nIDResource, bool bGrayscale, CImageList& ImgList) { - const int ImageCount = 22; - const int imageHeight = imageWidth - 1; - LoadHiColImageList(nIDResource, nIDResourceMask, imageWidth, imageHeight, ImageCount, bGrayscale, ImgList); + const int ImageCount = 26; + const int orgImageHeight = orgImageWidth - 1; + const int newImageHeight = newImageWidth - 1; + LoadHiColImageList(nIDResource, orgImageWidth, orgImageHeight, newImageWidth, newImageHeight, ImageCount, bGrayscale, ImgList); } /** @@ -2055,7 +2216,7 @@ void CMainFrame::OnUpdateFrameTitle(BOOL bAddToTitle) { CFrameWnd::OnUpdateFrameTitle(bAddToTitle); - if (m_wndTabBar.m_hWnd) + if (m_wndTabBar.m_hWnd != nullptr) m_wndTabBar.UpdateTabs(); } @@ -2115,17 +2276,10 @@ BOOL CMainFrame::OnToolTipText(UINT, NMHDR* pNMHDR, LRESULT* pResult) // this is the command id, not the button index AfxExtractSubString(strTipText, strFullText.c_str(), 1, '\n'); } -#ifndef _UNICODE - if (pNMHDR->code == TTN_NEEDTEXTA) - lstrcpyn(pTTTA->szText, strTipText, countof(pTTTA->szText)); - else - _mbstowcsz(pTTTW->szText, strTipText, countof(pTTTW->szText)); -#else if (pNMHDR->code == TTN_NEEDTEXTA) - _wcstombsz(pTTTA->szText, strTipText, countof(pTTTA->szText)); + _wcstombsz(pTTTA->szText, strTipText, static_cast(std::size(pTTTA->szText))); else - lstrcpyn(pTTTW->szText, strTipText, countof(pTTTW->szText)); -#endif + lstrcpyn(pTTTW->szText, strTipText, static_cast(std::size(pTTTW->szText))); *pResult = 0; // bring the tooltip window above other popup windows @@ -2170,7 +2324,7 @@ bool CMainFrame::AskCloseConfirmation() void CMainFrame::OnHelpReleasenotes() { const String sPath = paths::ConcatPath(env::GetProgPath(), RelNotes); - ShellExecute(NULL, _T("open"), sPath.c_str(), NULL, NULL, SW_SHOWNORMAL); + shell::Open(sPath.c_str()); } /** @@ -2179,7 +2333,7 @@ void CMainFrame::OnHelpReleasenotes() */ void CMainFrame::OnHelpTranslations() { - ShellExecute(NULL, _T("open"), TranslationsUrl, NULL, NULL, SW_SHOWNORMAL); + shell::Open(TranslationsUrl); } /** @@ -2273,14 +2427,31 @@ bool CMainFrame::DoOpenConflict(const String& conflictFile, const String strDesc return conflictCompared; } +bool CMainFrame::DoSelfCompare(UINT nID, const String& file, const String strDesc[] /*= nullptr*/) +{ + String ext = paths::FindExtension(file); + TempFilePtr wTemp(new TempFile()); + String copiedFile = wTemp->Create(_T("self-compare_"), ext); + m_tempFiles.push_back(wTemp); + + TFile(file).copyTo(copiedFile); + + String strDesc2[2] = { + (strDesc && !strDesc[0].empty()) ? strDesc[0] : _("Original File"), + (strDesc && !strDesc[1].empty()) ? strDesc[1] : _("") }; + DWORD dwFlags[2] = {FFILEOPEN_READONLY | FFILEOPEN_NOMRU, FFILEOPEN_NOMRU}; + PathContext tmpPathContext(copiedFile, file); + return DoFileOpen(nID, &tmpPathContext, dwFlags, strDesc2); +} + /** * @brief Get type of frame (File/Folder compare). * @param [in] pFrame Pointer to frame to check. * @return FRAMETYPE of the given frame. */ -CMainFrame::FRAMETYPE CMainFrame::GetFrameType(const CFrameWnd * pFrame) const +CMainFrame::FRAMETYPE CMainFrame::GetFrameType(const CFrameWnd * pFrame) { - bool bMergeFrame = !!pFrame->IsKindOf(RUNTIME_CLASS(CChildFrame)); + bool bMergeFrame = !!pFrame->IsKindOf(RUNTIME_CLASS(CMergeEditFrame)); bool bHexMergeFrame = !!pFrame->IsKindOf(RUNTIME_CLASS(CHexMergeFrame)); bool bImgMergeFrame = !!pFrame->IsKindOf(RUNTIME_CLASS(CImgMergeFrame)); bool bDirFrame = !!pFrame->IsKindOf(RUNTIME_CLASS(CDirFrame)); @@ -2306,12 +2477,28 @@ void CMainFrame::OnPluginsList() dlg.DoModal(); } -void CMainFrame::OnDiffOptionsDropDown(NMHDR* pNMHDR, LRESULT* pResult) +void CMainFrame::OnToolbarButtonDropDown(NMHDR* pNMHDR, LRESULT* pResult) { LPNMTOOLBAR pToolBar = reinterpret_cast(pNMHDR); ClientToScreen(&(pToolBar->rcButton)); BCMenu menu; - VERIFY(menu.LoadMenu(IDR_POPUP_DIFF_OPTIONS)); + int id; + switch (pToolBar->iItem) + { + case ID_FILE_NEW: + id = IDR_POPUP_NEW; + break; + case ID_FILE_OPEN: + id = IDR_POPUP_OPEN; + break; + case ID_FILE_SAVE: + id = IDR_POPUP_SAVE; + break; + default: + id = IDR_POPUP_DIFF_OPTIONS; + break; + } + VERIFY(menu.LoadMenu(id)); theApp.TranslateMenu(menu.m_hMenu); CMenu* pPopup = menu.GetSubMenu(0); if (pPopup != nullptr) @@ -2333,15 +2520,15 @@ void CMainFrame::OnUpdateDiffWhitespace(CCmdUI* pCmdUI) pCmdUI->Enable(); } -void CMainFrame::OnDiffCaseSensitive() +void CMainFrame::OnDiffIgnoreCase() { GetOptionsMgr()->SaveOption(OPT_CMP_IGNORE_CASE, !GetOptionsMgr()->GetBool(OPT_CMP_IGNORE_CASE)); ApplyDiffOptions(); } -void CMainFrame::OnUpdateDiffCaseSensitive(CCmdUI* pCmdUI) +void CMainFrame::OnUpdateDiffIgnoreCase(CCmdUI* pCmdUI) { - pCmdUI->SetCheck(!GetOptionsMgr()->GetBool(OPT_CMP_IGNORE_CASE)); + pCmdUI->SetCheck(GetOptionsMgr()->GetBool(OPT_CMP_IGNORE_CASE)); pCmdUI->Enable(); } @@ -2357,6 +2544,18 @@ void CMainFrame::OnUpdateDiffIgnoreEOL(CCmdUI* pCmdUI) pCmdUI->Enable(); } +void CMainFrame::OnDiffIgnoreCP() +{ + GetOptionsMgr()->SaveOption(OPT_CMP_IGNORE_CODEPAGE, !GetOptionsMgr()->GetBool(OPT_CMP_IGNORE_CODEPAGE)); + ApplyDiffOptions(); +} + +void CMainFrame::OnUpdateDiffIgnoreCP(CCmdUI* pCmdUI) +{ + pCmdUI->SetCheck(GetOptionsMgr()->GetBool(OPT_CMP_IGNORE_CODEPAGE)); + pCmdUI->Enable(); +} + void CMainFrame::OnIncludeSubfolders() { GetOptionsMgr()->SaveOption(OPT_CMP_INCLUDE_SUBDIRS, !GetOptionsMgr()->GetBool(OPT_CMP_INCLUDE_SUBDIRS)); @@ -2387,7 +2586,7 @@ void CMainFrame::OnUpdateCompareMethod(CCmdUI* pCmdUI) void CMainFrame::OnMRUs(UINT nID) { std::vector mrus = JumpList::GetRecentDocs(GetOptionsMgr()->GetInt(OPT_MRU_MAX)); - const size_t idx = nID - ID_MRU_FIRST; + const size_t idx = static_cast(nID) - ID_MRU_FIRST; if (idx < mrus.size()) { MergeCmdLineInfo cmdInfo((_T("\"") + mrus[idx].path + _T("\" ") + mrus[idx].params).c_str()); @@ -2398,9 +2597,10 @@ void CMainFrame::OnMRUs(UINT nID) void CMainFrame::OnUpdateNoMRUs(CCmdUI* pCmdUI) { // append the MRU submenu - HMENU hMenu = GetSubmenu(AfxGetMainWnd()->GetMenu()->m_hMenu, ID_FILE_NEW, false); - if (hMenu == NULL) + CMenu *pMenu = pCmdUI->m_pSubMenu ? pCmdUI->m_pSubMenu : pCmdUI->m_pMenu; + if (pMenu == nullptr) return; + HMENU hMenu = pMenu->m_hMenu; // empty the menu size_t i = ::GetMenuItemCount(hMenu); @@ -2436,6 +2636,94 @@ void CMainFrame::OnUpdatePluginName(CCmdUI* pCmdUI) pCmdUI->SetText(_T("")); } +/** + * @brief Move to next file + */ +void CMainFrame::OnNextFile() +{ + if (IMergeDoc* pMergeDoc = GetActiveIMergeDoc()) + if (CDirDoc* pDirDoc = pMergeDoc->GetDirDoc()) + pDirDoc->MoveToNextFile(pMergeDoc); +} + +/** + * @brief Called when Move to next file is updated + */ +void CMainFrame::OnUpdateNextFile(CCmdUI* pCmdUI) +{ + bool enabled = false; + if (IMergeDoc* pMergeDoc = GetActiveIMergeDoc()) + if (CDirDoc* pDirDoc = pMergeDoc->GetDirDoc()) + enabled = !pDirDoc->IsLastFile(); + pCmdUI->Enable(enabled); +} + +/** + * @brief Move to previous file + */ +void CMainFrame::OnPrevFile() +{ + if (IMergeDoc* pMergeDoc = GetActiveIMergeDoc()) + if (CDirDoc* pDirDoc = pMergeDoc->GetDirDoc()) + pDirDoc->MoveToPrevFile(pMergeDoc); +} + +/** + * @brief Called when Move to previous file is updated + */ +void CMainFrame::OnUpdatePrevFile(CCmdUI* pCmdUI) +{ + bool enabled = false; + if (IMergeDoc* pMergeDoc = GetActiveIMergeDoc()) + if (CDirDoc* pDirDoc = pMergeDoc->GetDirDoc()) + enabled = !pDirDoc->IsFirstFile(); + pCmdUI->Enable(enabled); +} + +/** + * @brief Move to first file + */ +void CMainFrame::OnFirstFile() +{ + if (IMergeDoc* pMergeDoc = GetActiveIMergeDoc()) + if (CDirDoc* pDirDoc = pMergeDoc->GetDirDoc()) + pDirDoc->MoveToFirstFile(pMergeDoc); +} + +/** + * @brief Called when Move to first file is updated + */ +void CMainFrame::OnUpdateFirstFile(CCmdUI* pCmdUI) +{ + bool enabled = false; + if (IMergeDoc* pMergeDoc = GetActiveIMergeDoc()) + if (CDirDoc* pDirDoc = pMergeDoc->GetDirDoc()) + enabled = !pDirDoc->IsFirstFile(); + pCmdUI->Enable(enabled); +} + +/** + * @brief Move to last file + */ +void CMainFrame::OnLastFile() +{ + if (IMergeDoc* pMergeDoc = GetActiveIMergeDoc()) + if (CDirDoc* pDirDoc = pMergeDoc->GetDirDoc()) + pDirDoc->MoveToLastFile(pMergeDoc); +} + +/** + * @brief Called when Move to last file item is updated + */ +void CMainFrame::OnUpdateLastFile(CCmdUI* pCmdUI) +{ + bool enabled = false; + if (IMergeDoc* pMergeDoc = GetActiveIMergeDoc()) + if (CDirDoc* pDirDoc = pMergeDoc->GetDirDoc()) + enabled = !pDirDoc->IsLastFile(); + pCmdUI->Enable(enabled); +} + void CMainFrame::ReloadMenu() { // set the menu of the main frame window @@ -2446,7 +2734,7 @@ void CMainFrame::ReloadMenu() HMENU hNewMergeMenu = pMainFrame->NewMergeViewMenu(); HMENU hNewImgMergeMenu = pMainFrame->NewImgMergeViewMenu(); HMENU hNewDirMenu = pMainFrame->NewDirViewMenu(); - if (hNewDefaultMenu && hNewMergeMenu && hNewDirMenu) + if (hNewDefaultMenu != nullptr && hNewMergeMenu != nullptr && hNewDirMenu != nullptr) { // Note : for Windows98 compatibility, use FromHandle and not Attach/Detach CMenu * pNewDefaultMenu = CMenu::FromHandle(hNewDefaultMenu); @@ -2455,10 +2743,10 @@ void CMainFrame::ReloadMenu() CMenu * pNewDirMenu = CMenu::FromHandle(hNewDirMenu); CWnd *pFrame = CWnd::FromHandle(::GetWindow(pMainFrame->m_hWndMDIClient, GW_CHILD)); - while (pFrame) + while (pFrame != nullptr) { - if (pFrame->IsKindOf(RUNTIME_CLASS(CChildFrame))) - static_cast(pFrame)->SetSharedMenu(hNewMergeMenu); + if (pFrame->IsKindOf(RUNTIME_CLASS(CMergeEditFrame))) + static_cast(pFrame)->SetSharedMenu(hNewMergeMenu); if (pFrame->IsKindOf(RUNTIME_CLASS(CHexMergeFrame))) static_cast(pFrame)->SetSharedMenu(hNewMergeMenu); if (pFrame->IsKindOf(RUNTIME_CLASS(CImgMergeFrame))) @@ -2471,30 +2759,30 @@ void CMainFrame::ReloadMenu() } CFrameWnd *pActiveFrame = pMainFrame->GetActiveFrame(); - if (pActiveFrame) + if (pActiveFrame != nullptr) { - if (pActiveFrame->IsKindOf(RUNTIME_CLASS(CChildFrame))) - pMainFrame->MDISetMenu(pNewMergeMenu, NULL); + if (pActiveFrame->IsKindOf(RUNTIME_CLASS(CMergeEditFrame))) + pMainFrame->MDISetMenu(pNewMergeMenu, nullptr); else if (pActiveFrame->IsKindOf(RUNTIME_CLASS(CHexMergeFrame))) - pMainFrame->MDISetMenu(pNewMergeMenu, NULL); + pMainFrame->MDISetMenu(pNewMergeMenu, nullptr); else if (pActiveFrame->IsKindOf(RUNTIME_CLASS(CImgMergeFrame))) - pMainFrame->MDISetMenu(pNewImgMergeMenu, NULL); + pMainFrame->MDISetMenu(pNewImgMergeMenu, nullptr); else if (pActiveFrame->IsKindOf(RUNTIME_CLASS(CDirFrame))) - pMainFrame->MDISetMenu(pNewDirMenu, NULL); + pMainFrame->MDISetMenu(pNewDirMenu, nullptr); else - pMainFrame->MDISetMenu(pNewDefaultMenu, NULL); + pMainFrame->MDISetMenu(pNewDefaultMenu, nullptr); } else - pMainFrame->MDISetMenu(pNewDefaultMenu, NULL); + pMainFrame->MDISetMenu(pNewDefaultMenu, nullptr); // Don't delete the old menu // There is a bug in BCMenu or in Windows98 : the new menu does not // appear correctly if we destroy the old one - // if (pOldDefaultMenu) + // if (pOldDefaultMenu != nullptr) // pOldDefaultMenu->DestroyMenu(); - // if (pOldMergeMenu) + // if (pOldMergeMenu != nullptr) // pOldMergeMenu->DestroyMenu(); - // if (pOldDirMenu) + // if (pOldDirMenu = nullptr) // pOldDirMenu->DestroyMenu(); // m_hMenuDefault is used to redraw the main menu when we close a child frame @@ -2509,6 +2797,17 @@ void CMainFrame::ReloadMenu() } } +IMergeDoc* CMainFrame::GetActiveIMergeDoc() +{ + CFrameWnd* pFrame = GetActiveFrame(); + if (!pFrame) + return nullptr; + IMergeDoc* pMergeDoc = dynamic_cast(pFrame->GetActiveDocument()); + if (!pMergeDoc) + pMergeDoc = dynamic_cast(pFrame); + return pMergeDoc; +} + void CMainFrame::UpdateDocTitle() { CDocManager* pDocManager = AfxGetApp()->m_pDocManager; @@ -2528,3 +2827,72 @@ void CMainFrame::UpdateDocTitle() } } } + +void CMainFrame::OnAccelQuit() +{ + // TODO: Add your command handler code here + + SendMessage(WM_CLOSE); +} + +LRESULT CMainFrame::OnChildFrameAdded(WPARAM wParam, LPARAM lParam) +{ + for (int i = 0; i < m_arrChild.GetSize(); ++i) + { + if (reinterpret_cast(lParam) == m_arrChild.GetAt(i)) + { + return 0; + } + } + + m_arrChild.InsertAt(0, (CMDIChildWnd*)lParam); + + return 1; +} + +LRESULT CMainFrame::OnChildFrameRemoved(WPARAM wParam, LPARAM lParam) +{ + for (int i = 0; i < m_arrChild.GetSize(); ++i) + { + if (reinterpret_cast(lParam) == m_arrChild.GetAt(i)) + { + m_arrChild.RemoveAt(i); + break; + } + } + + return 1; +} + +LRESULT CMainFrame::OnChildFrameActivate(WPARAM wParam, LPARAM lParam) +{ + for (int i = 0; i < m_arrChild.GetSize(); ++i) + { + if (reinterpret_cast(lParam) == m_arrChild.GetAt(i)) + { + CMDIChildWnd* pMDIChild = m_arrChild.GetAt(i); + if (pMDIChild->IsIconic()) + pMDIChild->ShowWindow(SW_RESTORE); + MDIActivate(pMDIChild); + break; + } + } + + return 1; +} +// put lParam as index 0 in m_arrChild +LRESULT CMainFrame::OnChildFrameActivated(WPARAM wParam, LPARAM lParam) +{ + for (int i = 0; i < m_arrChild.GetSize(); ++i) + { + if (reinterpret_cast(lParam) == m_arrChild.GetAt(i)) + { + m_arrChild.RemoveAt(i); + break; + } + } + + m_arrChild.InsertAt(0, (CMDIChildWnd*)lParam); + + return 1; +}