// Author: Dean Grimm
// SPDX-License-Identifier: GPL-2.0-or-later
/////////////////////////////////////////////////////////////////////////////
-/**
+/**
* @file Merge.cpp
*
* @brief Defines the class behaviors for the application.
#include "OptionsMgr.h"
#include "OptionsInit.h"
#include "RegOptionsMgr.h"
+#include "IniOptionsMgr.h"
#include "OpenDoc.h"
#include "OpenFrm.h"
#include "OpenView.h"
#include "DirView.h"
#include "PropBackups.h"
#include "FileOrFolderSelect.h"
-#include "paths.h"
#include "FileFilterHelper.h"
#include "LineFiltersList.h"
+#include "SubstitutionFiltersList.h"
#include "SyntaxColors.h"
#include "CCrystalTextMarkers.h"
#include "OptionsSyntaxColors.h"
#include "stringdiffs.h"
#include "TFile.h"
#include "paths.h"
+#include "Shell.h"
#include "CompareStats.h"
#include "TestMain.h"
#include "charsets.h" // For shutdown cleanup
, m_mainThreadScripts(nullptr)
, m_nLastCompareResult(0)
, m_bNonInteractive(false)
-, m_pOptions(new CRegOptionsMgr())
+, m_pOptions(CreateOptionManager())
, m_pGlobalFileFilter(new FileFilterHelper())
, m_nActiveOperations(0)
, m_pLangDlg(new CLanguageSelect())
, m_bEscShutdown(false)
-, m_bExitIfNoDiff(MergeCmdLineInfo::Disabled)
+, m_bExitIfNoDiff(MergeCmdLineInfo::ExitNoDiff::Disabled)
, m_pLineFilters(new LineFiltersList())
+, m_pSubstitutionFiltersList(new SubstitutionFiltersList())
, m_pSyntaxColors(new SyntaxColors())
, m_pMarkers(new CCrystalTextMarkers())
, m_bMergingMode(false)
// Place all significant initialization in InitInstance
}
+/**
+ * @brief Chose which options manager should be initialized.
+ * @return IniOptionsMgr if initial config file exists,
+ * CRegOptionsMgr otherwise.
+ */
+COptionsMgr *CreateOptionManager()
+{
+ if (CIniOptionsMgr::CheckIfIniFileExist())
+ {
+ return new CIniOptionsMgr();
+ }
+ else
+ {
+ return new CRegOptionsMgr();
+ }
+}
+
CMergeApp::~CMergeApp()
{
strdiff::Close();
// This is the name of the company of the original author (Dean Grimm)
SetRegistryKey(_T("Thingamahoochie"));
- bool bSingleInstance = cmdInfo.m_bSingleInstance.has_value() ?
- *cmdInfo.m_bSingleInstance : GetOptionsMgr()->GetBool(OPT_SINGLE_INSTANCE);
+ int nSingleInstance = cmdInfo.m_nSingleInstance.has_value() ?
+ *cmdInfo.m_nSingleInstance : GetOptionsMgr()->GetInt(OPT_SINGLE_INSTANCE);
// Create exclusion mutex name
TCHAR szDesktopName[MAX_PATH] = _T("Win9xDesktop");
DWORD dwLengthNeeded;
- GetUserObjectInformation(GetThreadDesktop(GetCurrentThreadId()), UOI_NAME,
+ GetUserObjectInformation(GetThreadDesktop(GetCurrentThreadId()), UOI_NAME,
szDesktopName, sizeof(szDesktopName), &dwLengthNeeded);
TCHAR szMutexName[MAX_PATH + 40];
// Combine window class name and desktop name to form a unique mutex name.
HANDLE hMutex = CreateMutex(nullptr, FALSE, szMutexName);
if (hMutex != nullptr)
WaitForSingleObject(hMutex, INFINITE);
- if (bSingleInstance && GetLastError() == ERROR_ALREADY_EXISTS)
+ if (nSingleInstance != 0 && GetLastError() == ERROR_ALREADY_EXISTS)
{
// Activate previous instance and send commandline to it
HWND hWnd = FindWindow(CMainFrame::szClassName, nullptr);
{
ReleaseMutex(hMutex);
CloseHandle(hMutex);
+ if (nSingleInstance > 1)
+ {
+ DWORD dwProcessId = 0;
+ GetWindowThreadProcessId(hWnd, &dwProcessId);
+ HANDLE hProcess = OpenProcess(SYNCHRONIZE, FALSE, dwProcessId);
+ if (hProcess)
+ WaitForSingleObject(hProcess, INFINITE);
+ }
return FALSE;
}
}
m_pLineFilters->Import(oldFilter);
}
+ if (m_pSubstitutionFiltersList != nullptr)
+ m_pSubstitutionFiltersList->Initialize(GetOptionsMgr());
+
// Check if filter folder is set, and create it if not
String pathMyFolders = GetOptionsMgr()->GetString(OPT_FILTER_USERPATH);
if (pathMyFolders.empty())
theApp.OpenFileToExternalEditor(paths::ConcatPath(env::GetProgPath(), ContributorsPath));
}
+static void OpenUrl(int&)
+{
+ shell::Open(WinMergeURL);
+}
+
// App command to run the dialog
void CMergeApp::OnAppAbout()
{
CAboutDlg aboutDlg;
aboutDlg.m_onclick_contributers += Poco::delegate(OpenContributersFile);
+ aboutDlg.m_onclick_url += Poco::delegate(OpenUrl);
aboutDlg.DoModal();
aboutDlg.m_onclick_contributers.clear();
+ aboutDlg.m_onclick_url.clear();
}
/////////////////////////////////////////////////////////////////////////////
* good place to do cleanups.
* @return Application's exit value (returned from WinMain()).
*/
-int CMergeApp::ExitInstance()
+int CMergeApp::ExitInstance()
{
charsets_cleanup();
ClearTempfolder(temp);
// Cleanup left over tempfiles from previous instances.
- // Normally this should not neet to do anything - but if for some reason
+ // Normally this should not need to do anything - but if for some reason
// WinMerge did not delete temp files this makes sure they are removed.
CleanupWMtemp();
// Create the message box dialog.
CMessageBoxDialog dlgMessage(pParentWnd, lpszPrompt, _T(""), nType | MB_RIGHT_ALIGN,
nIDPrompt);
-
+
if (m_pMainWnd->IsIconic())
m_pMainWnd->ShowWindow(SW_RESTORE);
return idle;
}
-BOOL CMergeApp::OnIdle(LONG lCount)
+BOOL CMergeApp::OnIdle(LONG lCount)
{
if (CWinApp::OnIdle(lCount))
return TRUE;
if (m_bNonInteractive && IsReallyIdle())
m_pMainWnd->PostMessage(WM_CLOSE, 0, 0);
- static_cast<CRegOptionsMgr *>(GetOptionsMgr())->CloseKeys();
+ if (typeid(*GetOptionsMgr()) == typeid(CRegOptionsMgr))
+ {
+ static_cast<CRegOptionsMgr*>(GetOptionsMgr())->CloseKeys();
+ }
return FALSE;
}
else if (cmdInfo.m_Files.GetSize() == 1)
{
String sFilepath = cmdInfo.m_Files[0];
- if (IsProjectFile(sFilepath))
+ if (cmdInfo.m_bSelfCompare)
+ {
+ strDesc[0] = cmdInfo.m_sLeftDesc;
+ strDesc[1] = cmdInfo.m_sRightDesc;
+ bCompared = pMainFrame->DoSelfCompare(IDOK, sFilepath, strDesc);
+ }
+ else if (IsProjectFile(sFilepath))
{
bCompared = LoadAndOpenProjectFile(sFilepath);
}
{
DWORD dwFlags[3] = {cmdInfo.m_dwLeftFlags, cmdInfo.m_dwRightFlags, FFILEOPEN_NONE};
bCompared = pMainFrame->DoFileOpen(&cmdInfo.m_Files,
- dwFlags, strDesc, cmdInfo.m_sReportFile, cmdInfo.m_bRecurse, nullptr,
+ dwFlags, strDesc, cmdInfo.m_sReportFile, cmdInfo.m_bRecurse, nullptr,
cmdInfo.m_sPreDiffer, infoUnpacker.get());
}
}
}
/**
- * @brief Open file, if it exists, else open url
- */
-void CMergeApp::OpenFileOrUrl(LPCTSTR szFile, LPCTSTR szUrl)
-{
- if (paths::DoesPathExist(szFile) == paths::IS_EXISTING_FILE)
- ShellExecute(nullptr, _T("open"), _T("notepad.exe"), szFile, nullptr, SW_SHOWNORMAL);
- else
- ShellExecute(nullptr, _T("open"), szUrl, nullptr, nullptr, SW_SHOWNORMAL);
-}
-
-/**
* @brief Show Help - this is for opening help from outside mainframe.
* @param [in] helpLocation Location inside help, if `nullptr` main help is opened.
*/
if (paths::DoesPathExist(sPath) == paths::IS_EXISTING_FILE)
::HtmlHelp(nullptr, sPath.c_str(), HH_DISPLAY_TOC, NULL);
else
- ShellExecute(nullptr, _T("open"), DocsURL, nullptr, nullptr, SW_SHOWNORMAL);
+ shell::Open(DocsURL);
}
else
{
String path;
String filename;
String ext;
-
+
paths::SplitFilename(paths::GetLongPath(pszPath), &path, &filename, &ext);
// Determine backup folder
{
success = !!CopyFileW(TFile(pszPath).wpath().c_str(), TFile(bakPath).wpath().c_str(), FALSE);
}
-
+
if (!success)
{
String msg = strutils::format_string1(
if (bFileExists && bFileRO)
{
UINT userChoice = 0;
-
+
// Don't ask again if its already asked
if (bApplyToAll)
userChoice = IDYES;
// Overwrite read-only file
case IDYESTOALL:
bApplyToAll = true; // Don't ask again (no break here)
+ [[fallthrough]];
case IDYES:
CFile::GetStatus(strSavePath.c_str(), status);
status.m_mtime = 0; // Avoid unwanted changes
CFile::SetStatus(strSavePath.c_str(), status);
nRetVal = IDYES;
break;
-
+
// Save to new filename (single) /skip this item (multiple)
case IDNO:
if (!bMultiFile)
return true;
}
-/**
+/**
* @brief Read project and perform comparison specified
* @param [in] sProject Full path to project file.
* @return `true` if loading project file and starting compare succeeded.
ProjectFile project;
if (!LoadProjectFile(sProject, project))
return false;
-
+
bool rtn = true;
for (auto& projItem : project.Items())
{
*/
void CMergeApp::AddToRecentProjectsMRU(LPCTSTR sPathName)
{
- // sPathName will be added to the top of the MRU list.
+ // sPathName will be added to the top of the MRU list.
// If sPathName already exists in the MRU list, it will be moved to the top
if (m_pRecentFileList != nullptr) {
m_pRecentFileList->Add(sPathName);