[svn.haxx.se] · SVN Dev · SVN Users · SVN Org · TSVN Dev · TSVN Users · Subclipse Dev · Subclipse Users · this month's index

[TSVN] [PATCH] Support for making patch straight onto the clipboard

From: Will Dean <svn_at_indcomp.co.uk>
Date: 2004-11-05 16:12:28 CET

Hi,

The appended patch adds a new button to the Create Patch 'Save As' dialog
to allow the patch to be created on the clipboard.

Comments:

1. The new dialog resource is in UK English - bizarrely, if I change it to
US English in VS, it actually gets put in a neutral language, which seemed
worse.

2. I've moved all the CreatePatch code out of InitApplication into a
function of its own. I'm not sure if there is an unspoken engagement in a
competition to have the longest InitApplication function in MFC programming
history, but it certainly looks a bit like it...! If anybody's upset by
this change, then I don't mind if the code gets put back into InitInstance.

3. I stole the code for writing an CStringA to the clipboard from elsewhere
in the project. The same code appeared about three times, so I re-factored
it into utils.cpp.

I've created a new dialog with no title and one button on it, and one new
string resource. I don't know how the translation stuff works, or what the
impact of this is on it.

Cheers,

Will

Index: TortoiseMerge/BaseView.cpp
===================================================================
--- TortoiseMerge/BaseView.cpp (revision 1911)
+++ TortoiseMerge/BaseView.cpp (working copy)
@@ -1657,18 +1657,7 @@
          CStringA sCopyDataASCII = CStringA(sCopyData);
          if (!sCopyDataASCII.IsEmpty())
          {
- if (OpenClipboard())
- {
- EmptyClipboard();
- HGLOBAL hClipboardData;
- hClipboardData = GlobalAlloc(GMEM_DDESHARE, sCopyDataASCII.GetLength()+1);
- char * pchData;
- pchData = (char*)GlobalLock(hClipboardData);
- strcpy(pchData, (LPCSTR)sCopyDataASCII);
- GlobalUnlock(hClipboardData);
- SetClipboardData(CF_TEXT,hClipboardData);
- CloseClipboard();
- } // if (OpenClipboard())
+ CUtils::WriteAsciiStringToClipboard(sCopyDataASCII);
          } // if (!sCopyData.IsEmpty())
  }

Index: TortoiseProc/SVNProgressDlg.cpp
===================================================================
--- TortoiseProc/SVNProgressDlg.cpp (revision 1911)
+++ TortoiseProc/SVNProgressDlg.cpp (working copy)
@@ -970,18 +970,7 @@
                                                                  sAction, sPath, sMime);
                                                          sClipdata += CStringA(sLogCopyText);
                                                  }
- if (OpenClipboard())
- {
- EmptyClipboard();
- HGLOBAL hClipboardData;
- hClipboardData = GlobalAlloc(GMEM_DDESHARE, sClipdata.GetLength()+1);
- char * pchData;
- pchData = (char*)GlobalLock(hClipboardData);
- strcpy(pchData, (LPCSTR)sClipdata);
- GlobalUnlock(hClipboardData);
- SetClipboardData(CF_TEXT,hClipboardData);
- CloseClipboard();
- } // if (OpenClipboard())
+ CUtils::WriteAsciiStringToClipboard(sClipdata);
                                          }
                                  } // if (GetKeyState(VK_CONTROL)&0x8000)
                          } // if (selIndex >= 0)
Index: TortoiseProc/TortoiseProc.h
===================================================================
--- TortoiseProc/TortoiseProc.h (revision 1911)
+++ TortoiseProc/TortoiseProc.h (working copy)
@@ -67,6 +67,10 @@
   * or makes your car start emitting strange noises when you start it up.
   * This code has no bugs, just undocumented features!
   */
+
+// Fwd references for classes
+class CCmdLineParser;
+
  class CTortoiseProcApp : public CWinApp
  {
  public:
@@ -80,6 +84,11 @@
          void CrashProgram();
  // Implementation

+private:
+ static UINT_PTR CALLBACK CreatePatchFileOpenHook(HWND hDlg, UINT uiMsg,
WPARAM wParam, LPARAM lParam);
+ void CreatePatch(const CCmdLineParser& parser);
+
+
          DECLARE_MESSAGE_MAP()
  private:
          HANDLE m_mutex;
Index: TortoiseProc/stdafx.h
===================================================================
--- TortoiseProc/stdafx.h (revision 1911)
+++ TortoiseProc/stdafx.h (working copy)
@@ -94,6 +96,7 @@
  #include <shlguid.h>
  #include <uxtheme.h>
  #include <tmschema.h>
+#include <dlgs.h>
  #pragma warning(pop)

  #pragma warning(push)
Index: TortoiseProc/Utils.cpp
===================================================================
--- TortoiseProc/Utils.cpp (revision 1911)
+++ TortoiseProc/Utils.cpp (working copy)
@@ -721,3 +721,26 @@
                  pos++;
          }
  }
+
+
+bool CUtils::WriteAsciiStringToClipboard(const CStringA& sClipdata, HWND
hOwningWnd)
+{
+ //TODO The error handling in here is not exactly sparkling!
+
+ if (OpenClipboard(hOwningWnd))
+ {
+ EmptyClipboard();
+ HGLOBAL hClipboardData;
+ hClipboardData = GlobalAlloc(GMEM_DDESHARE, sClipdata.GetLength()+1);
+ char * pchData;
+ pchData = (char*)GlobalLock(hClipboardData);
+ strcpy(pchData, (LPCSTR)sClipdata);
+ GlobalUnlock(hClipboardData);
+ SetClipboardData(CF_TEXT,hClipboardData);
+ CloseClipboard();
+
+ return true;
+ } // if (OpenClipboard())
+
+ return false;
+}
Index: TortoiseProc/LogDlg.cpp
===================================================================
--- TortoiseProc/LogDlg.cpp (revision 1911)
+++ TortoiseProc/LogDlg.cpp (working copy)
@@ -500,18 +500,7 @@
                                                          m_arLogPaths.GetAt(nItem));
                                                  sClipdata += CStringA(sLogCopyText);
                                          }
- if (OpenClipboard())
- {
- EmptyClipboard();
- HGLOBAL hClipboardData;
- hClipboardData = GlobalAlloc(GMEM_DDESHARE, sClipdata.GetLength()+1);
- char * pchData;
- pchData = (char*)GlobalLock(hClipboardData);
- strcpy(pchData, (LPCSTR)sClipdata);
- GlobalUnlock(hClipboardData);
- SetClipboardData(CF_TEXT,hClipboardData);
- CloseClipboard();
- } // if (OpenClipboard())
+ CUtils::WriteAsciiStringToClipboard(sClipdata);
                                  }
                          }
                  }
Index: TortoiseProc/resource.h
===================================================================
--- TortoiseProc/resource.h (revision 1911)
+++ TortoiseProc/resource.h (working copy)
@@ -1,6 +1,6 @@
  //{{NO_DEPENDENCIES}}
  // Microsoft Visual C++ generated include file.
-// Used by f:\Development\Svn\TortoiseSVN\src\Resources\TortoiseProcENG.rc
+// Used by n:\will\svn\TortoiseSVN\src\Resources\TortoiseProcENG.rc
  //
  #define IDR_MANIFEST 1
  #define IDR_MAINFRAME 1
@@ -45,6 +45,7 @@
  #define IDD_PROPERTIES 177
  #define IDD_REPOCREATE 178
  #define IDD_STATGRAPH 179
+#define IDD_PATCH_FILE_OPEN_CUSTOM 180
  #define IDS_CHSTAT_FILECOL 1000
  #define IDS_CHSTAT_WCCOL 1001
  #define IDS_CHSTAT_REPOCOL 1002
@@ -194,6 +195,7 @@
  #define IDC_GRAPH 1131
  #define IDC_BUTTON1 1132
  #define IDC_STATBUTTON 1132
+#define IDC_PATCH_TO_CLIPBOARD 1132
  #define IDC_GRAPHCOMBO 1133
  #define IDC_GRAPHTYPELABEL 1134
  #define IDS_MSGBOX_DONOTSHOWAGAIN 1153
@@ -445,12 +447,13 @@
  #define IDS_SVNERR_RUNCLEANUP 4001
  #define IDS_SVNERR_UPDATEFIRST 4002
  #define IDS_SVNERR_CLEANUPORFRESHCHECKOUT 4003
+#define IDS_CLIPBOARD_PROGRESS_DEST 4100

  // Next default values for new objects
  //
  #ifdef APSTUDIO_INVOKED
  #ifndef APSTUDIO_READONLY_SYMBOLS
-#define _APS_NEXT_RESOURCE_VALUE 180
+#define _APS_NEXT_RESOURCE_VALUE 181
  #define _APS_NEXT_COMMAND_VALUE 32771
  #define _APS_NEXT_CONTROL_VALUE 1135
  #define _APS_NEXT_SYMED_VALUE 101
Index: TortoiseProc/Utils.h
===================================================================
--- TortoiseProc/Utils.h (revision 1911)
+++ TortoiseProc/Utils.h (working copy)
@@ -145,4 +145,9 @@
          static BOOL CheckForEmptyDiff(CString sDiffPath);

          static void RemoveAccelerators(CString& text);
+
+ /**
+ * Writes an ASCII CString to the clipboard in CF_TEXT format
+ */
+ static bool WriteAsciiStringToClipboard(const CStringA& sClipdata, HWND
hOwningWnd = NULL);
  };
Index: TortoiseProc/TortoiseProc.cpp
===================================================================
--- TortoiseProc/TortoiseProc.cpp (revision 1911)
+++ TortoiseProc/TortoiseProc.cpp (working copy)
@@ -64,6 +64,9 @@
  #define PWND (hWndExplorer ? CWnd::FromHandle(hWndExplorer) : NULL)
  #define EXPLORERHWND (IsWindow(hWndExplorer) ? hWndExplorer : NULL)

+// This is a fake filename which we use to fill-in the create-patch
file-open dialog
+#define PATCH_TO_CLIPBOARD_PSEUDO_FILENAME _T(".TSVNPatchToClipboard")
+
  BEGIN_MESSAGE_MAP(CTortoiseProcApp, CWinApp)
          ON_COMMAND(ID_HELP, CWinApp::OnHelp)
  END_MESSAGE_MAP()
@@ -1304,77 +1307,8 @@
                  //#region createpatch
                  if (comVal.Compare(_T("createpatch"))==0)
                  {
- CString path = CUtils::GetLongPathname(parser.GetVal(_T("path")));
- OPENFILENAME ofn; // common dialog box structure
- TCHAR szFile[MAX_PATH]; // buffer for file name
- ZeroMemory(szFile, sizeof(szFile));
- // Initialize OPENFILENAME
- ZeroMemory(&ofn, sizeof(OPENFILENAME));
- //ofn.lStructSize = sizeof(OPENFILENAME);
- ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400; //to stay compatible
with NT4
- ofn.hwndOwner = (EXPLORERHWND);
- ofn.lpstrFile = szFile;
- ofn.nMaxFile = sizeof(szFile)/sizeof(TCHAR);
- CString temp;
- temp.LoadString(IDS_REPOBROWSE_SAVEAS);
- CUtils::RemoveAccelerators(temp);
- if (temp.IsEmpty())
- ofn.lpstrTitle = NULL;
- else
- ofn.lpstrTitle = temp;
- ofn.Flags = OFN_OVERWRITEPROMPT;
-
- CString sFilter;
- sFilter.LoadString(IDS_PATCHFILEFILTER);
- TCHAR * pszFilters = new TCHAR[sFilter.GetLength()+4];
- _tcscpy (pszFilters, sFilter);
- // Replace '|' delimeters with '\0's
- TCHAR *ptr = pszFilters + _tcslen(pszFilters); //set ptr at the NULL
- while (ptr != pszFilters)
- {
- if (*ptr == '|')
- *ptr = '\0';
- ptr--;
- } // while (ptr != pszFilters)
- ofn.lpstrFilter = pszFilters;
- ofn.nFilterIndex = 1;
- // Display the Open dialog box.
- if (GetSaveFileName(&ofn)==FALSE)
- {
- delete [] pszFilters;
- return FALSE;
- } // if (GetSaveFileName(&ofn)==FALSE)
- delete [] pszFilters;
-
- CProgressDlg progDlg;
- temp.LoadString(IDS_PROC_SAVEPATCHTO);
- progDlg.SetLine(1, temp, true);
- progDlg.SetLine(2, ofn.lpstrFile, true);
- temp.LoadString(IDS_PROC_PATCHTITLE);
- progDlg.SetTitle(temp);
- progDlg.SetShowProgressBar(false);
- progDlg.ShowModeless(CWnd::FromHandle(EXPLORERHWND));
- //progDlg.SetAnimation(IDR_ANIMATION);
-
- path = path.TrimRight('\\');
- CString sDir;
- if (!PathIsDirectory(path))
- {
- SetCurrentDirectory(path.Left(path.ReverseFind('\\')));
- sDir = path.Mid(path.ReverseFind('\\')+1);
- }
- else
- SetCurrentDirectory(path);
-
- SVN svn;
- if (!svn.Diff(sDir, SVNRev::REV_BASE, sDir, SVNRev::REV_WC, TRUE,
FALSE, FALSE, _T(""), ofn.lpstrFile))
- {
- progDlg.Stop();
- ::MessageBox((EXPLORERHWND), svn.GetLastErrorMessage(),
_T("TortoiseSVN"), MB_ICONERROR);
- DeleteFile(ofn.lpstrFile);
- } // if (!svn.Diff(path, SVNRev::REV_WC, path, SVNRev::REV_BASE, TRUE,
FALSE, FALSE, _T(""), sSavePath))
- progDlg.Stop();
- } // if (comVal.Compare(_T("cat"))==0)
+ CreatePatch(parser);
+ } // if (comVal.Compare(_T("createpatch"))==0)
                  //#endregion
                  //#region updatecheck
                  if (comVal.Compare(_T("updatecheck"))==0)
@@ -1435,3 +1369,142 @@
          // application, rather than start the application's message pump.
          return FALSE;
  }
+
+
+UINT_PTR CALLBACK
+CTortoiseProcApp::CreatePatchFileOpenHook(HWND hDlg, UINT uiMsg, WPARAM
wParam, LPARAM /*lParam*/)
+{
+ if(uiMsg == WM_COMMAND && LOWORD(wParam) == IDC_PATCH_TO_CLIPBOARD)
+ {
+ HWND hFileDialog = GetParent(hDlg);
+
+ CString strFilename = CUtils::GetTempFile() +
PATCH_TO_CLIPBOARD_PSEUDO_FILENAME;
+
+ CommDlg_OpenSave_SetControlText(hFileDialog, edt1, (LPCTSTR)strFilename);
+
+ PostMessage(hFileDialog, WM_COMMAND, MAKEWPARAM(IDOK, BM_CLICK),
(LPARAM)(GetDlgItem(hDlg, IDOK)));
+ }
+ return 0;
+}
+
+void
+CTortoiseProcApp::CreatePatch(const CCmdLineParser& parser)
+{
+ CString path = CUtils::GetLongPathname(parser.GetVal(_T("path")));
+ OPENFILENAME ofn; // common dialog box structure
+ TCHAR szFile[MAX_PATH]; // buffer for file name
+ ZeroMemory(szFile, sizeof(szFile));
+ // Initialize OPENFILENAME
+ ZeroMemory(&ofn, sizeof(OPENFILENAME));
+ //ofn.lStructSize = sizeof(OPENFILENAME);
+ ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400; //to stay compatible
with NT4
+ ofn.hwndOwner = (EXPLORERHWND);
+ ofn.lpstrFile = szFile;
+ ofn.nMaxFile = sizeof(szFile)/sizeof(TCHAR);
+ CString temp;
+ temp.LoadString(IDS_REPOBROWSE_SAVEAS);
+ CUtils::RemoveAccelerators(temp);
+ if (temp.IsEmpty())
+ ofn.lpstrTitle = NULL;
+ else
+ ofn.lpstrTitle = temp;
+ ofn.Flags = OFN_OVERWRITEPROMPT | OFN_ENABLETEMPLATE | OFN_EXPLORER |
OFN_ENABLEHOOK;
+
+ ofn.hInstance = AfxGetResourceHandle();
+ ofn.lpTemplateName = MAKEINTRESOURCE(IDD_PATCH_FILE_OPEN_CUSTOM);
+ ofn.lpfnHook = CreatePatchFileOpenHook;
+
+ CString sFilter;
+ sFilter.LoadString(IDS_PATCHFILEFILTER);
+ TCHAR * pszFilters = new TCHAR[sFilter.GetLength()+4];
+ _tcscpy (pszFilters, sFilter);
+ // Replace '|' delimeters with '\0's
+ TCHAR *ptr = pszFilters + _tcslen(pszFilters); //set ptr at the NULL
+ while (ptr != pszFilters)
+ {
+ if (*ptr == '|')
+ *ptr = '\0';
+ ptr--;
+ } // while (ptr != pszFilters)
+ ofn.lpstrFilter = pszFilters;
+ ofn.nFilterIndex = 1;
+ // Display the Open dialog box.
+ if (GetSaveFileName(&ofn)==FALSE)
+ {
+ delete [] pszFilters;
+ return;
+ } // if (GetSaveFileName(&ofn)==FALSE)
+ delete [] pszFilters;
+
+ bool bToClipboard = _tcsstr(ofn.lpstrFile,
PATCH_TO_CLIPBOARD_PSEUDO_FILENAME) != NULL;
+
+ CProgressDlg progDlg;
+ temp.LoadString(IDS_PROC_SAVEPATCHTO);
+ progDlg.SetLine(1, temp, true);
+ CString strProgressDest(ofn.lpstrFile);
+ if(bToClipboard)
+ {
+ strProgressDest.LoadString(IDS_CLIPBOARD_PROGRESS_DEST);
+ }
+ progDlg.SetLine(2, strProgressDest, true);
+ temp.LoadString(IDS_PROC_PATCHTITLE);
+ progDlg.SetTitle(temp);
+ progDlg.SetShowProgressBar(false);
+ progDlg.ShowModeless(CWnd::FromHandle(EXPLORERHWND));
+ //progDlg.SetAnimation(IDR_ANIMATION);
+
+
+ CString strTempPatchFile = CUtils::GetTempFile();
+
+ path = path.TrimRight('\\');
+ CString sDir;
+ if (!PathIsDirectory(path))
+ {
+ SetCurrentDirectory(path.Left(path.ReverseFind('\\')));
+ sDir = path.Mid(path.ReverseFind('\\')+1);
+ }
+ else
+ SetCurrentDirectory(path);
+
+ SVN svn;
+ if (!svn.Diff(sDir, SVNRev::REV_BASE, sDir, SVNRev::REV_WC, TRUE, FALSE,
FALSE, _T(""), strTempPatchFile))
+ {
+ progDlg.Stop();
+ ::MessageBox((EXPLORERHWND), svn.GetLastErrorMessage(),
_T("TortoiseSVN"), MB_ICONERROR);
+ } // if (!svn.Diff(path, SVNRev::REV_WC, path, SVNRev::REV_BASE, TRUE,
FALSE, FALSE, _T(""), sSavePath))
+
+ if(bToClipboard)
+ {
+ // The user actually asked for the patch to be written to the clipboard
+
+ CStringA sClipdata;
+
+ FILE* inFile = _tfopen(strTempPatchFile, _T("rb"));
+ if(inFile)
+ {
+ char chunkBuffer[16384];
+ while(!feof(inFile))
+ {
+ size_t readLength = fread(chunkBuffer, 1, sizeof(chunkBuffer), inFile);
+
+ sClipdata += CStringA(chunkBuffer, (int)readLength);
+ }
+ fclose(inFile);
+
+ CUtils::WriteAsciiStringToClipboard(sClipdata);
+
+ }
+ }
+ else
+ {
+ // We should copy the temporary file to the user's selected file
+ CopyFile(strTempPatchFile, ofn.lpstrFile, FALSE);
+ }
+
+ progDlg.Stop();
+ DeleteFile(strTempPatchFile);
+
+}
+
+
+
Index: Resources/TortoiseProcENG.rc
===================================================================
--- Resources/TortoiseProcENG.rc (revision 1911)
+++ Resources/TortoiseProcENG.rc (working copy)
@@ -1504,6 +1504,11 @@
      IDS_STATGRAPH_COMMITSBYAUTHORY "commits"
  END

+STRINGTABLE
+BEGIN
+ IDS_CLIPBOARD_PROGRESS_DEST "Clipboard"
+END
+
  #endif // English (U.S.) resources
  /////////////////////////////////////////////////////////////////////////////

@@ -1619,7 +1624,52 @@
  /////////////////////////////////////////////////////////////////////////////

+/////////////////////////////////////////////////////////////////////////////
+// English (U.K.) resources

+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_PATCH_FILE_OPEN_CUSTOM DIALOGEX 0, 0, 94, 28
+STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | DS_CONTROL | WS_CHILD |
+ WS_CLIPSIBLINGS | WS_SYSMENU
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ PUSHBUTTON "Save To Clipboard",IDC_PATCH_TO_CLIPBOARD,7,7,80,14
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO
+BEGIN
+ IDD_PATCH_FILE_OPEN_CUSTOM, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 87
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 21
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+#endif // English (U.K.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
  #ifndef APSTUDIO_INVOKED
  /////////////////////////////////////////////////////////////////////////////
  //

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tortoisesvn.tigris.org
For additional commands, e-mail: dev-help@tortoisesvn.tigris.org
Received on Fri Nov 5 16:13:03 2004

This is an archived mail posted to the TortoiseSVN Dev mailing list.