Skip to content

Commit

Permalink
Clipboard Compare (WinMerge#1147)
Browse files Browse the repository at this point in the history
  • Loading branch information
sdottaka committed Jan 23, 2022
1 parent 2b5516e commit 026281c
Show file tree
Hide file tree
Showing 53 changed files with 1,240 additions and 362 deletions.
9 changes: 9 additions & 0 deletions Docs/Manual/EN/Command_line.xml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@

<arg choice="opt" rep="norepeat"><option>/self-compare</option></arg>

<arg choice="opt" rep="norepeat"><option>/clipboard-compare</option></arg>

<arg><option>/minimize</option></arg>

<arg><option>/maximize</option></arg>
Expand Down Expand Up @@ -389,6 +391,13 @@
</listitem>
</varlistentry>

<varlistentry>
<term><option>/clipboard-compare</option></term>
<listitem>
<para>Compares the two most recent contents of the clipboard history.</para>
</listitem>
</varlistentry>

<varlistentry>
<indexterm>
<primary>WinMerge window</primary>
Expand Down
9 changes: 9 additions & 0 deletions Docs/Manual/JP/Command_line.xml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@

<arg choice="opt" rep="norepeat"><option>/self-compare</option></arg>

<arg choice="opt" rep="norepeat"><option>/clipboard-compare</option></arg>

<arg><option>/minimize</option></arg>

<arg><option>/maximize</option></arg>
Expand Down Expand Up @@ -388,6 +390,13 @@
</listitem>
</varlistentry>

<varlistentry>
<term><option>/clipboard-compare</option></term>
<listitem>
<para>クリップボード履歴の直近2つの内容を比較します。</para>
</listitem>
</varlistentry>

<varlistentry>
<indexterm>
<primary>WinMergeウインドウ</primary>
Expand Down
152 changes: 152 additions & 0 deletions Src/ClipboardHistory.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
/**
* @file ClipboardHistory.cpp
*
* @brief Implementation for Clipboard history functions
*/

#include "StdAfx.h"
#include "ClipboardHistory.h"
#include "ClipBoard.h"
#include "Concurrent.h"
#include "UniFile.h"

#ifdef _WIN64

#include <winrt/windows.foundation.collections.h>
#include <winrt/windows.applicationmodel.datatransfer.h>
#include <winrt/windows.graphics.imaging.h>
#include <winrt/windows.storage.streams.h>

using namespace winrt::Windows::ApplicationModel::DataTransfer;
using namespace winrt::Windows::Graphics::Imaging;
using namespace winrt::Windows::Storage;

#endif

namespace ClipboardHistory
{
namespace impl
{
std::shared_ptr<TempFile> CreateTempTextFile(const String& text)
{
std::shared_ptr<TempFile> pTempFile(new TempFile());
pTempFile->Create(_T("CLP"), L".txt");
String path = pTempFile->GetPath();
UniStdioFile file;
if (file.OpenCreateUtf8(path))
{
file.WriteString(text);
file.Close();
}
return pTempFile;
}

String GetClipboardText()
{
String text;
GetFromClipboard(text, nullptr);
return text;
}

#ifdef _WIN64
std::shared_ptr<TempFile> CreateTempBitmapFile(const DataPackageView& dataPackageView)
{
std::shared_ptr<TempFile> pTempFile(new TempFile());
pTempFile->Create(_T("CLP"), _T(".png"));

auto streamReference = dataPackageView.GetBitmapAsync().get();
auto inputStream = streamReference.OpenReadAsync().get();
auto decoder = BitmapDecoder::CreateAsync(inputStream).get();
auto bitmap = decoder.GetSoftwareBitmapAsync().get();

auto outputFile = StorageFile::GetFileFromPathAsync(pTempFile->GetPath()).get();
auto outputStream = outputFile.OpenAsync(FileAccessMode::ReadWrite).get();
auto encoder = BitmapEncoder::CreateAsync(BitmapEncoder::PngEncoderId(), outputStream).get();
encoder.SetSoftwareBitmap(bitmap);
encoder.FlushAsync().get();

return pTempFile;
}
#endif

std::vector<Item> GetItems(unsigned num)
{
std::vector<Item> result;
#ifdef _WIN64
try
{
auto historyItems = Clipboard::GetHistoryItemsAsync().get();
auto items = historyItems.Items();
for (unsigned int i = 0; i < num; ++i)
{
result.emplace_back();
auto& item = result.back();
if (i < items.Size())
{
try
{
auto dataPackageView = items.GetAt(i).Content();
item.timestamp = winrt::clock::to_time_t(items.GetAt(i).Timestamp());
if (dataPackageView.Contains(StandardDataFormats::Text()))
{
item.pTextTempFile = CreateTempTextFile(dataPackageView.GetTextAsync().get().c_str());
}
if (dataPackageView.Contains(StandardDataFormats::Bitmap()))
{
item.pBitmapTempFile = CreateTempBitmapFile(dataPackageView);
}
if (!item.pTextTempFile && !item.pBitmapTempFile)
{
item.pTextTempFile = CreateTempTextFile(_T(""));
}
}
catch (const winrt::hresult_error& e)
{
item.pTextTempFile = CreateTempTextFile(e.message().c_str());
}
}
else
{
if (i == 0)
time(&item.timestamp);
item.pTextTempFile = CreateTempTextFile(i == 0 ?
GetClipboardText() :
(!Clipboard::IsHistoryEnabled() ? _("Clipboard history is disabled.\r\nTo enable clipboard history, press Windows logo key + V and then click the Turn on button.") : _T("")));
}
}
}
catch (const winrt::hresult_error&)
{
for (unsigned int i = 0; i < num; ++i)
{
result.emplace_back();
auto& item = result.back();
if (i == 0)
time(&item.timestamp);
item.pTextTempFile = CreateTempTextFile(
i == 0 ? GetClipboardText() : _("This system does not support clipboard history."));
}
}
#else
for (unsigned int i = 0; i < num; ++i)
{
result.emplace_back();
auto& item = result.back();
if (i == 0)
time(&item.timestamp);
item.pTextTempFile = CreateTempTextFile(
i == 0 ? GetClipboardText() : _("The 32-bit version of WinMerge does not support Clipboard Compare"));
}
#endif
return result;
}
}

std::vector<Item> GetItems(unsigned num)
{
auto task = Concurrent::CreateTask([num] {
return impl::GetItems(num);
});
return task.Get();
}
}
23 changes: 23 additions & 0 deletions Src/ClipboardHistory.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
* @file ClipboardHistory.h
*
* @brief Declaration file for Clipboard history functions
*/
#pragma once

#include "UnicodeString.h"
#include "TempFile.h"
#include <memory>
#include <vector>
#include <ctime>

namespace ClipboardHistory
{
struct Item
{
time_t timestamp;
std::shared_ptr<TempFile> pTextTempFile;
std::shared_ptr<TempFile> pBitmapTempFile;
};
std::vector<Item> GetItems(unsigned num);
}
51 changes: 51 additions & 0 deletions Src/MainFrm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@
#include "TFile.h"
#include "Shell.h"
#include "WindowsManagerDialog.h"
#include "ClipboardHistory.h"
#include "locality.h"

using std::vector;
using boost::begin;
Expand Down Expand Up @@ -223,6 +225,8 @@ BEGIN_MESSAGE_MAP(CMainFrame, CMDIFrameWnd)
ON_COMMAND(ID_FILE_OPENPROJECT, OnFileOpenProject)
ON_COMMAND(ID_FILE_SAVEPROJECT, OnSaveProject)
ON_COMMAND(ID_FILE_OPENCONFLICT, OnFileOpenConflict)
ON_COMMAND(ID_FILE_OPENCLIPBOARD, OnFileOpenClipboard)
ON_COMMAND(ID_EDIT_PASTE, OnFileOpenClipboard)
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)
Expand Down Expand Up @@ -2536,6 +2540,53 @@ void CMainFrame::OnFileOpenConflict()
}
}

/**
* @brief Called when user selects File/Open Clipboard
*/
void CMainFrame::OnFileOpenClipboard()
{
DoOpenClipboard();
}

bool CMainFrame::DoOpenClipboard(UINT nID, int nBuffers /*= 2*/, const DWORD dwFlags[] /*= nullptr*/,
const String strDesc[] /*= nullptr*/, const PackingInfo* infoUnpacker /*= nullptr*/,
const PrediffingInfo* infoPrediffer /*= nullptr*/, const OpenFileParams* pOpenParams /*= nullptr*/)
{
auto historyItems = ClipboardHistory::GetItems(nBuffers);

String strDesc2[3];
DWORD dwFlags2[3];
for (int i = 0; i < nBuffers; ++i)
{
int64_t t = historyItems[nBuffers - i - 1].timestamp;
String timestr = t == 0 ? _T("---") : locality::TimeString(&t);
strDesc2[i] = (strDesc && !strDesc[i].empty()) ?
strDesc[i] : strutils::format(_("Clipboard at %s"), timestr);
dwFlags2[i] = (dwFlags ? dwFlags[i] : 0) | FFILEOPEN_NOMRU;
}
for (int i = 0; i < 2; ++i)
{
PathContext tmpPathContext;
for (int pane = 0; pane < nBuffers; ++pane)
{
auto item = historyItems[nBuffers - pane - 1];
if (i == 0 && item.pBitmapTempFile)
{
tmpPathContext.SetPath(pane, item.pBitmapTempFile->GetPath());
m_tempFiles.push_back(item.pBitmapTempFile);
}
if (i == 1 && item.pTextTempFile)
{
tmpPathContext.SetPath(pane, item.pTextTempFile->GetPath());
m_tempFiles.push_back(item.pTextTempFile);
}
}
if (tmpPathContext.GetSize() == nBuffers)
DoFileOpen(nID, &tmpPathContext, dwFlags2, strDesc2, _T(""), infoUnpacker, infoPrediffer, pOpenParams);
}
return true;
}

/**
* @brief Select and open conflict file for resolving.
* This function lets user to select conflict file to resolve.
Expand Down
4 changes: 4 additions & 0 deletions Src/MainFrm.h
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,9 @@ class CMainFrame : public CMDIFrameWnd
const PrediffingInfo * infoPrediffer = nullptr,
const OpenFileParams *pOpenParams = nullptr);
bool DoOpenConflict(const String& conflictFile, const String strDesc[] = nullptr, bool checked = false);
bool DoOpenClipboard(UINT nID = 0, int nBuffers = 2, const DWORD dwFlags[] = nullptr, const String strDesc[] = nullptr,
const PackingInfo* infoUnpacker = nullptr, const PrediffingInfo * infoPrediffer = nullptr,
const OpenFileParams* pOpenParams = nullptr);
bool DoSelfCompare(UINT nID, const String& file, const String strDesc[] = nullptr,
const PackingInfo* infoUnpacker = nullptr, const PrediffingInfo * infoPrediffer = nullptr,
const OpenFileParams* pOpenParams = nullptr);
Expand Down Expand Up @@ -332,6 +335,7 @@ class CMainFrame : public CMDIFrameWnd
afx_msg void OnHelpReleasenotes();
afx_msg void OnHelpTranslations();
afx_msg void OnFileOpenConflict();
afx_msg void OnFileOpenClipboard();
afx_msg void OnPluginsList();
afx_msg void OnUpdatePluginName(CCmdUI* pCmdUI);
afx_msg void OnUpdateStatusNum(CCmdUI* pCmdUI);
Expand Down
15 changes: 10 additions & 5 deletions Src/Merge.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -795,15 +795,20 @@ bool CMergeApp::ParseArgsAndDoOpen(MergeCmdLineInfo& cmdInfo, CMainFrame* pMainF
}
else if (cmdInfo.m_Files.GetSize() == 0) // if there are no input args, we can check the display file dialog flag
{
if (!cmdInfo.m_bNewCompare)
if (cmdInfo.m_bNewCompare)
{
bool showFiles = m_pOptions->GetBool(OPT_SHOW_SELECT_FILES_AT_STARTUP);
if (showFiles)
pMainFrame->DoFileOrFolderOpen();
bCompared = pMainFrame->DoFileNew(nID, 2, strDesc, infoPrediffer.get(), pOpenParams.get());
}
else if (cmdInfo.m_bClipboardCompare)
{
DWORD dwFlags[3] = {cmdInfo.m_dwLeftFlags, cmdInfo.m_dwRightFlags, FFILEOPEN_NONE};
bCompared = pMainFrame->DoOpenClipboard(nID, 2, dwFlags, strDesc, infoUnpacker.get(), infoPrediffer.get(), pOpenParams.get());
}
else
{
bCompared = pMainFrame->DoFileNew(nID, 2, strDesc, infoPrediffer.get(), pOpenParams.get());
bool showFiles = m_pOptions->GetBool(OPT_SHOW_SELECT_FILES_AT_STARTUP);
if (showFiles)
pMainFrame->DoFileOrFolderOpen();
}
}
}
Expand Down
13 changes: 13 additions & 0 deletions Src/Merge.rc
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,7 @@ BEGIN
END
MENUITEM "&Open...\tCtrl+O", ID_FILE_OPEN
MENUITEM "Open Conflic&t File...", ID_FILE_OPENCONFLICT
MENUITEM "Open C&lipboard", ID_FILE_OPENCLIPBOARD
MENUITEM SEPARATOR
MENUITEM "Open Pro&ject...\tCtrl+J", ID_FILE_OPENPROJECT
MENUITEM "Sa&ve Project...", ID_FILE_SAVEPROJECT
Expand All @@ -244,6 +245,8 @@ BEGIN
END
POPUP "&Edit"
BEGIN
MENUITEM "&Paste\tCtrl+V", ID_EDIT_PASTE
MENUITEM SEPARATOR
MENUITEM "&Options...", ID_OPTIONS
END
POPUP "&View"
Expand Down Expand Up @@ -319,6 +322,7 @@ BEGIN
END
MENUITEM "&Open...\tCtrl+O", ID_FILE_OPEN
MENUITEM "Open Conflic&t File...", ID_FILE_OPENCONFLICT
MENUITEM "Open C&lipboard", ID_FILE_OPENCLIPBOARD
MENUITEM SEPARATOR
MENUITEM "Open Pro&ject...\tCtrl+J", ID_FILE_OPENPROJECT
MENUITEM "Sa&ve Project...", ID_FILE_SAVEPROJECT
Expand Down Expand Up @@ -477,6 +481,7 @@ BEGIN
END
MENUITEM "&Open...\tCtrl+O", ID_FILE_OPEN
MENUITEM "Open Conflic&t File...", ID_FILE_OPENCONFLICT
MENUITEM "Open C&lipboard", ID_FILE_OPENCLIPBOARD
MENUITEM SEPARATOR
MENUITEM "Open Pro&ject...\tCtrl+J", ID_FILE_OPENPROJECT
MENUITEM "Sa&ve Project...", ID_FILE_SAVEPROJECT
Expand Down Expand Up @@ -4011,6 +4016,14 @@ BEGIN
IDS_FILTER_APPLIED "Filter applied"
END

STRINGTABLE
BEGIN
IDS_CLIPBOARDHISTORY_TIME "Clipboard at %s"
IDS_CLIPBOARDHISTORY_DISABLED "Clipboard history is disabled.\r\nTo enable clipboard history, press Windows logo key + V and then click the Turn on button."
IDS_CLIPBOARDHISTORY_NOT_SUPPORTED1 "This system does not support clipboard history."
IDS_CLIPBOARDHISTORY_NOT_SUPPORTED2 "The 32-bit version of WinMerge does not support Clipboard Compare"
END

#endif // English (United States) resources
/////////////////////////////////////////////////////////////////////////////

Expand Down
Loading

0 comments on commit 026281c

Please sign in to comment.