Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- Index: src/CommitMonitor.cpp
- ===================================================================
- --- src/CommitMonitor.cpp (revision 605)
- +++ src/CommitMonitor.cpp (working copy)
- @@ -33,6 +33,9 @@
- #define STRUCT_IOVEC_DEFINED
- #include "sasl.h"
- +#include "Http.h"
- +#include "ReviewBoardXml.h"
- +
- // Global Variables:
- HINSTANCE hInst; // current instance
- HANDLE g_mutex = 0;
- @@ -47,6 +50,8 @@
- UNREFERENCED_PARAMETER(hPrevInstance);
- UNREFERENCED_PARAMETER(lpCmdLine);
- UNREFERENCED_PARAMETER(nCmdShow);
- + gHTTP.Init("reviews.reviewboard.org");
- + gReviewBoard;
- SetDllDirectory(L"");
- ::OleInitialize(NULL);
- @@ -116,7 +121,7 @@
- else
- {
- //only one instance of this application part allowed
- - g_mutex = ::CreateMutex(NULL, FALSE, APPNAME_MUTEX);
- + g_mutex = ::CreateMutexW(NULL, FALSE, APPNAME_MUTEX);
- if (g_mutex != NULL)
- {
- @@ -141,6 +146,8 @@
- if (hiddenWindow.RegisterAndCreateWindow())
- {
- + gReviewBoard.Load();
- +
- if ((snarlIface.GetVersionEx() != Snarl::M_FAILED)&&(Snarl::SnarlInterface::GetSnarlWindow() != NULL))
- {
- wstring imgPath = CAppUtils::GetAppDataDir()+L"\\CM.png";
- @@ -189,7 +196,8 @@
- // unregister with Snarl
- snarlIface.UnregisterApp();
- }
- -
- + gReviewBoard_Cleanup;
- + gHTTP_Cleanup;
- return (int) msg.wParam;
- }
- Index: src/CommitMonitor.vcxproj
- ===================================================================
- --- src/CommitMonitor.vcxproj (revision 605)
- +++ src/CommitMonitor.vcxproj (working copy)
- @@ -51,7 +51,7 @@
- </PreBuildEvent>
- <ClCompile>
- <Optimization>Disabled</Optimization>
- - <AdditionalIncludeDirectories>..\ext\apr\include;..\ext\Subversion\Subversion\include;..\ext\apr-util\include;Resources;..\ext\scintilla\win32;..\ext\scintilla\src;..\ext\scintilla\lexers;..\ext\scintilla\lexlib;..\ext\scintilla\include;..\ext\cyrus-sasl\include;..\ext\snarl;..\ext\BlowFish;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
- + <AdditionalIncludeDirectories>J:\dev\poco\include;..\ext\rapidxml;..\ext\apr\include;..\ext\Subversion\Subversion\include;..\ext\apr-util\include;Resources;..\ext\scintilla\win32;..\ext\scintilla\src;..\ext\scintilla\lexers;..\ext\scintilla\lexlib;..\ext\scintilla\include;..\ext\cyrus-sasl\include;..\ext\snarl;..\ext\BlowFish;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
- <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;SVN_DEBUG;APR_DECLARE_STATIC;APU_DECLARE_STATIC;STATIC_BUILD;SCI_LEXER;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <MinimalRebuild>true</MinimalRebuild>
- <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
- @@ -65,7 +65,7 @@
- <ResourceOutputFileName>$(IntDir)%(Filename).res</ResourceOutputFileName>
- </ResourceCompile>
- <Link>
- - <AdditionalDependencies>Ws2_32.lib;Mswsock.lib;Rpcrt4.lib;Imm32.lib;Secur32.lib;Crypt32.lib;..\ext\apr\debug_win32\libapr.lib;..\ext\apr-util\debug_win32\libaprutil.lib;..\ext\neon\debug_win32\libneon.lib;..\ext\Subversion\debug_win32\libsvn_client.lib;..\ext\Subversion\debug_win32\libsvn_delta.lib;..\ext\Subversion\debug_win32\libsvn_diff.lib;..\ext\Subversion\debug_win32\libsvn_ra.lib;..\ext\Subversion\debug_win32\libsvn_ra_neon.lib;..\ext\Subversion\debug_win32\libsvn_ra_serf.lib;..\ext\Subversion\debug_win32\libsvn_ra_svn.lib;..\ext\Subversion\debug_win32\libsvn_repos.lib;..\ext\Subversion\debug_win32\libsvn_subr.lib;..\ext\Subversion\debug_win32\libsvn_wc.lib;..\ext\cyrus-sasl\debug_win32\libsasls.lib;..\ext\serf\debug_win32\libserf.lib;..\ext\sqlite\debug_win32\sqlite.lib;%(AdditionalDependencies)</AdditionalDependencies>
- + <AdditionalDependencies>PocoFoundationmtd.lib;PocoNetmtd.lib;PocoUtilmtd.lib;Ws2_32.lib;Mswsock.lib;Rpcrt4.lib;Imm32.lib;Secur32.lib;Crypt32.lib;..\ext\apr\debug_win32\libapr.lib;..\ext\apr-util\debug_win32\libaprutil.lib;..\ext\neon\debug_win32\libneon.lib;..\ext\Subversion\debug_win32\libsvn_client.lib;..\ext\Subversion\debug_win32\libsvn_delta.lib;..\ext\Subversion\debug_win32\libsvn_diff.lib;..\ext\Subversion\debug_win32\libsvn_ra.lib;..\ext\Subversion\debug_win32\libsvn_ra_neon.lib;..\ext\Subversion\debug_win32\libsvn_ra_serf.lib;..\ext\Subversion\debug_win32\libsvn_ra_svn.lib;..\ext\Subversion\debug_win32\libsvn_repos.lib;..\ext\Subversion\debug_win32\libsvn_subr.lib;..\ext\Subversion\debug_win32\libsvn_wc.lib;..\ext\cyrus-sasl\debug_win32\libsasls.lib;..\ext\serf\debug_win32\libserf.lib;..\ext\sqlite\debug_win32\sqlite.lib;%(AdditionalDependencies)</AdditionalDependencies>
- <IgnoreSpecificDefaultLibraries>winspool.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- <SubSystem>Windows</SubSystem>
- @@ -73,6 +73,7 @@
- <DataExecutionPrevention>
- </DataExecutionPrevention>
- <TargetMachine>MachineX86</TargetMachine>
- + <AdditionalLibraryDirectories>J:\dev\poco\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
- </Link>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- @@ -94,7 +95,7 @@
- <AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
- </ResourceCompile>
- <Link>
- - <AdditionalDependencies>Ws2_32.lib;Mswsock.lib;Rpcrt4.lib;Imm32.lib;Secur32.lib;Crypt32.lib;..\ext\apr\release_win32\libapr.lib;..\ext\apr-util\release_win32\libaprutil.lib;..\ext\neon\release_win32\libneon.lib;..\ext\Subversion\release_win32\libsvn_client.lib;..\ext\Subversion\release_win32\libsvn_delta.lib;..\ext\Subversion\release_win32\libsvn_diff.lib;..\ext\Subversion\release_win32\libsvn_ra.lib;..\ext\Subversion\release_win32\libsvn_ra_neon.lib;..\ext\Subversion\release_win32\libsvn_ra_serf.lib;..\ext\Subversion\release_win32\libsvn_ra_svn.lib;..\ext\Subversion\release_win32\libsvn_repos.lib;..\ext\Subversion\release_win32\libsvn_subr.lib;..\ext\Subversion\release_win32\libsvn_wc.lib;..\ext\cyrus-sasl\release_win32\libsasls.lib;..\ext\serf\release_win32\libserf.lib;..\ext\sqlite\debug_win32\sqlite.lib;%(AdditionalDependencies)</AdditionalDependencies>
- + <AdditionalDependencies>PocoFoundationmt.lib;PocoNetmt.lib;PocoUtilmt.lib;Ws2_32.lib;Mswsock.lib;Rpcrt4.lib;Imm32.lib;Secur32.lib;Crypt32.lib;..\ext\apr\release_win32\libapr.lib;..\ext\apr-util\release_win32\libaprutil.lib;..\ext\neon\release_win32\libneon.lib;..\ext\Subversion\release_win32\libsvn_client.lib;..\ext\Subversion\release_win32\libsvn_delta.lib;..\ext\Subversion\release_win32\libsvn_diff.lib;..\ext\Subversion\release_win32\libsvn_ra.lib;..\ext\Subversion\release_win32\libsvn_ra_neon.lib;..\ext\Subversion\release_win32\libsvn_ra_serf.lib;..\ext\Subversion\release_win32\libsvn_ra_svn.lib;..\ext\Subversion\release_win32\libsvn_repos.lib;..\ext\Subversion\release_win32\libsvn_subr.lib;..\ext\Subversion\release_win32\libsvn_wc.lib;..\ext\cyrus-sasl\release_win32\libsasls.lib;..\ext\serf\release_win32\libserf.lib;..\ext\sqlite\debug_win32\sqlite.lib;%(AdditionalDependencies)</AdditionalDependencies>
- <IgnoreSpecificDefaultLibraries>winspool.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- <SubSystem>Windows</SubSystem>
- @@ -323,10 +324,12 @@
- <ClCompile Include="DiffViewer.cpp" />
- <ClCompile Include="FindBar.cpp" />
- <ClCompile Include="HiddenWindow.cpp" />
- + <ClCompile Include="Http.cpp" />
- <ClCompile Include="MainDlg.cpp" />
- <ClCompile Include="OptionsDlg.cpp" />
- <ClCompile Include="PasswordDlg.cpp" />
- <ClCompile Include="ProgressDlg.cpp" />
- + <ClCompile Include="ReviewBoardXml.cpp" />
- <ClCompile Include="SCCS.cpp" />
- <ClCompile Include="SerializeUtils.cpp" />
- <ClCompile Include="StatusBarMsgWnd.cpp" />
- @@ -336,6 +339,7 @@
- </ClCompile>
- <ClCompile Include="SVN.cpp" />
- <ClCompile Include="SVNPool.cpp" />
- + <ClCompile Include="timesupport.cc" />
- <ClCompile Include="UpdateDlg.cpp" />
- <ClCompile Include="URLDlg.cpp" />
- <ClCompile Include="UrlInfo.cpp" />
- @@ -410,20 +414,25 @@
- <ClInclude Include="Accurev.h" />
- <ClInclude Include="Callback.h" />
- <ClInclude Include="CommitMonitor.h" />
- + <ClInclude Include="Convert.h" />
- <ClInclude Include="DiffViewer.h" />
- <ClInclude Include="FindBar.h" />
- <ClInclude Include="HiddenWindow.h" />
- + <ClInclude Include="Http.h" />
- <ClInclude Include="MainDlg.h" />
- <ClInclude Include="OptionsDlg.h" />
- <ClInclude Include="PasswordDlg.h" />
- <ClInclude Include="ProgressDlg.h" />
- <ClInclude Include="Resources\resource.h" />
- + <ClInclude Include="ReviewBoardXml.h" />
- <ClInclude Include="SCCS.h" />
- <ClInclude Include="SerializeUtils.h" />
- + <ClInclude Include="Singleton.h" />
- <ClInclude Include="StatusBarMsgWnd.h" />
- <ClInclude Include="stdafx.h" />
- <ClInclude Include="SVN.h" />
- <ClInclude Include="SVNPool.h" />
- + <ClInclude Include="timesupport.h" />
- <ClInclude Include="UpdateDlg.h" />
- <ClInclude Include="URLDlg.h" />
- <ClInclude Include="UrlInfo.h" />
- Index: src/CommitMonitor.vcxproj.filters
- ===================================================================
- --- src/CommitMonitor.vcxproj.filters (revision 605)
- +++ src/CommitMonitor.vcxproj.filters (working copy)
- @@ -243,6 +243,15 @@
- <ClCompile Include="..\ext\scintilla\win32\PlatWin.cxx">
- <Filter>Scintilla</Filter>
- </ClCompile>
- + <ClCompile Include="Http.cpp">
- + <Filter>Source Files</Filter>
- + </ClCompile>
- + <ClCompile Include="ReviewBoardXml.cpp">
- + <Filter>Source Files</Filter>
- + </ClCompile>
- + <ClCompile Include="timesupport.cc">
- + <Filter>Source Files</Filter>
- + </ClCompile>
- </ItemGroup>
- <ItemGroup>
- <ClInclude Include="AboutDlg.h">
- @@ -479,6 +488,21 @@
- <ClInclude Include="..\ext\scintilla\lexlib\LexerModule.h">
- <Filter>Scintilla</Filter>
- </ClInclude>
- + <ClInclude Include="Http.h">
- + <Filter>Header Files</Filter>
- + </ClInclude>
- + <ClInclude Include="ReviewBoardXml.h">
- + <Filter>Header Files</Filter>
- + </ClInclude>
- + <ClInclude Include="Convert.h">
- + <Filter>Header Files</Filter>
- + </ClInclude>
- + <ClInclude Include="Singleton.h">
- + <Filter>Header Files</Filter>
- + </ClInclude>
- + <ClInclude Include="timesupport.h">
- + <Filter>Header Files</Filter>
- + </ClInclude>
- </ItemGroup>
- <ItemGroup>
- <None Include="Resources\about.ico">
- Index: src/Convert.h
- ===================================================================
- --- src/Convert.h (revision 0)
- +++ src/Convert.h (revision 0)
- @@ -0,0 +1,164 @@
- +#ifndef CONVERT_H
- +#define CONVERT_H
- +
- +#include "stdafx.h"
- +#include <string>
- +#include <sstream>
- +
- +template <class out_type, class in_value>
- +class Converter
- +{
- +public:
- + static out_type convert(const in_value &t)
- + {
- + std::wstringstream stream;
- + stream << t;
- +
- + out_type result;
- + stream >> result;
- + return result;
- + }
- +};
- +
- +template <>
- +class Converter<std::wstring, std::wstring>
- +{
- +public:
- + static std::wstring convert(const std::wstring &t)
- + {
- + return t;
- + }
- +};
- +
- +template <class out_type, class in_value>
- +out_type convert(const in_value &t)
- +{
- + return Converter<out_type, in_value>::convert(t);
- +}
- +
- +#define BOM8A 0xEF
- +#define BOM8B 0xBB
- +#define BOM8C 0xBF
- +
- +/*
- +* Copyright (c) 2009, Helios (helios.vmg@gmail.com)
- +* All rights reserved.
- +*
- +* Redistribution and use in source and binary forms, with or without
- +* modification, are permitted provided that the following conditions are met:
- +* * Redistributions of source code must retain the above copyright notice,
- +* this list of conditions and the following disclaimer.
- +* * Redistributions in binary form must reproduce the above copyright
- +* notice, this list of conditions and the following disclaimer in the
- +* documentation and/or other materials provided with the distribution.
- +*
- +* THIS SOFTWARE IS PROVIDED BY HELIOS "AS IS" AND ANY EXPRESS OR IMPLIED
- +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- +* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- +* EVENT SHALL HELIOS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- +* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- +* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- +* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- +* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- +* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- +* OF THE POSSIBILITY OF SUCH DAMAGE.
- +*/
- +
- +typedef unsigned char uchar;
- +
- +/*
- +string: a UTF-8-encoded C string (nul terminated)
- +Return value: a wchar_t C string.
- +
- +The function handles memory allocation on its own.
- +
- +Limitations: Only handles the range [U+0000;U+FFFF], higher code points are
- +changed to '?'.
- +
- +Assumptions: sizeof(wchar_t)>=2
- +*/
- +wchar_t *UTF8_to_WChar(const char *string){
- + long b=0,
- + c=0;
- + if ((uchar)string[0]==BOM8A && (uchar)string[1]==BOM8B && (uchar)string[2]==BOM8C)
- + string+=3;
- + for (const char *a=string;*a;a++)
- + if (((uchar)*a)<128 || (*a&192)==192)
- + c++;
- + wchar_t *res=new wchar_t[c+1];
- + res[c]=0;
- + for (uchar *a=(uchar*)string;*a;a++){
- + if (!(*a&128))
- + //Byte represents an ASCII character. Direct copy will do.
- + res[b]=*a;
- + else if ((*a&192)==128)
- + //Byte is the middle of an encoded character. Ignore.
- + continue;
- + else if ((*a&224)==192)
- + //Byte represents the start of an encoded character in the range
- + //U+0080 to U+07FF
- + res[b]=((*a&31)<<6)|a[1]&63;
- + else if ((*a&240)==224)
- + //Byte represents the start of an encoded character in the range
- + //U+07FF to U+FFFF
- + res[b]=((*a&15)<<12)|((a[1]&63)<<6)|a[2]&63;
- + else if ((*a&248)==240){
- + //Byte represents the start of an encoded character beyond the
- + //U+FFFF limit of 16-bit integers
- + res[b]='?';
- + }
- + b++;
- + }
- + return res;
- +}
- +
- +//Do not call me.
- +long getUTF8size(const wchar_t *string){
- + if (!string)
- + return 0;
- + long res=0;
- + for (;*string;string++){
- + if (*string<0x80)
- + res++;
- + else if (*string<0x800)
- + res+=2;
- + else
- + res+=3;
- + }
- + return res;
- +}
- +
- +/*
- +string: a wchar_t C string (nul terminated)
- +Return value: a UTF-8-encoded C string.
- +
- +The function handles memory allocation on its own.
- +
- +Limitations: Only handles the range [U+0000;U+FFFF], higher code points are
- +changed to '?'.
- +
- +Assumptions: sizeof(wchar_t)>=2
- +*/
- +char *WChar_to_UTF8(const wchar_t *string){
- + long fSize=getUTF8size(string);
- + char *res=new char[fSize+1];
- + res[fSize]=0;
- + if (!string)
- + return res;
- + long b=0;
- + for (;*string;string++,b++){
- + if (*string<0x80)
- + res[b]=(char)*string;
- + else if (*string<0x800){
- + res[b++]=(*string>>6)|192;
- + res[b]=*string&63|128;
- + }else{
- + res[b++]=(*string>>12)|224;
- + res[b++]=((*string&4095)>>6)|128;
- + res[b]=*string&63|128;
- + }
- + }
- + return res;
- +}
- +
- +#endif
- Index: src/HiddenWindow.cpp
- ===================================================================
- --- src/HiddenWindow.cpp (revision 605)
- +++ src/HiddenWindow.cpp (working copy)
- @@ -34,7 +34,7 @@
- #include "OptionsDlg.h"
- #include "version.h"
- #include "SnarlInterface.h"
- -
- +#include "ReviewBoardXml.h"
- #include <cctype>
- #include <regex>
- using namespace std;
- @@ -345,6 +345,7 @@
- {
- // find the number of unread items
- int nNewCommits = 0;
- + int nNewReviews = gReviewBoard.GetUnreadReviews();
- const map<wstring, CUrlInfo> * pRead = m_UrlInfos.GetReadOnlyData();
- for (map<wstring, CUrlInfo>::const_iterator it = pRead->begin(); it != pRead->end(); ++it)
- {
- @@ -360,12 +361,39 @@
- m_SystemTray.hWnd = *this;
- m_SystemTray.uFlags = NIF_MESSAGE | NIF_TIP;
- m_SystemTray.uCallbackMessage = COMMITMONITOR_TASKBARCALLBACK;
- - if (nNewCommits)
- + if (nNewCommits || nNewReviews)
- {
- - if (nNewCommits == 1)
- - _stprintf_s(m_SystemTray.szTip, _countof(m_SystemTray.szTip), _T("CommitMonitor - %d new commit"), nNewCommits);
- + if(nNewReviews == 0)
- + {
- + if (nNewCommits == 1)
- + _stprintf_s(m_SystemTray.szTip, _countof(m_SystemTray.szTip), _T("CommitMonitor - %d new commit"), nNewCommits);
- + else
- + _stprintf_s(m_SystemTray.szTip, _countof(m_SystemTray.szTip), _T("CommitMonitor - %d new commits"), nNewCommits);
- + }
- else
- - _stprintf_s(m_SystemTray.szTip, _countof(m_SystemTray.szTip), _T("CommitMonitor - %d new commits"), nNewCommits);
- + {
- + if (nNewCommits == 0)
- + {
- + if (nNewReviews == 1)
- + _stprintf_s(m_SystemTray.szTip, _countof(m_SystemTray.szTip), _T("CommitMonitor - %d new review"), nNewReviews);
- + else
- + _stprintf_s(m_SystemTray.szTip, _countof(m_SystemTray.szTip), _T("CommitMonitor - %d new reviews"), nNewReviews);
- + }
- + else if(nNewCommits == 1)
- + {
- + if (nNewReviews == 1)
- + _stprintf_s(m_SystemTray.szTip, _countof(m_SystemTray.szTip), _T("CommitMonitor - %d new commit, %d new review"), nNewCommits, nNewReviews);
- + else
- + _stprintf_s(m_SystemTray.szTip, _countof(m_SystemTray.szTip), _T("CommitMonitor - %d new commit, %d new reviews"), nNewCommits, nNewReviews);
- + }
- + else
- + {
- + if (nNewReviews == 1)
- + _stprintf_s(m_SystemTray.szTip, _countof(m_SystemTray.szTip), _T("CommitMonitor - %d new commits, %d new review"), nNewCommits, nNewReviews);
- + else
- + _stprintf_s(m_SystemTray.szTip, _countof(m_SystemTray.szTip), _T("CommitMonitor - %d new commits, %d new reviews"), nNewCommits, nNewReviews);
- + }
- + }
- }
- else
- _tcscpy_s(m_SystemTray.szTip, _countof(m_SystemTray.szTip), _T("CommitMonitor"));
- @@ -679,7 +707,8 @@
- // won't block anything for too long.
- map<wstring,CUrlInfo> urlinfoReadOnly = *m_UrlInfos.GetReadOnlyData();
- m_UrlInfos.ReleaseReadOnlyData();
- -
- + bool needReviewUpdate = false;
- + int newreviews = 0;
- TCHAR infotextbuf[1024];
- TRACE(_T("monitor thread started\n"));
- const map<wstring,CUrlInfo> * pUrlInfoReadOnly = &urlinfoReadOnly;
- @@ -695,6 +724,13 @@
- }
- if (((it->second.monitored)&&((it->second.lastchecked + (mit*60)) < currenttime))||(m_UrlToWorkOn.size()))
- {
- + if(!needReviewUpdate && gReviewBoard.IsUrlMonitored(it->second.url))
- + {
- + needReviewUpdate = true;
- + // do update here, we're not currently blocking anything (update will ofc...)
- + newreviews = gReviewBoard.DoUpdate();
- + }
- +
- m_UrlToWorkOn.clear();
- if ((it->second.errNr == SVN_ERR_RA_NOT_AUTHORIZED)&&(!it->second.error.empty()))
- continue; // don't check if the last error was 'not authorized'
- @@ -740,9 +776,9 @@
- }
- if (!m_bRun)
- continue;
- - if (headrev > it->second.lastcheckedrev)
- + if (headrev > it->second.lastcheckedrev || gReviewBoard.GetNewReviewsForUrl(it->second.url))
- {
- - TRACE(_T("%s has updates! Last checked revision was %ld, HEAD revision is %ld\n"), it->first.c_str(), it->second.lastcheckedrev, headrev);
- + TRACE(_T("%s has updates! Last checked revision was %ld, HEAD revision is %ld or new reviews\n"), it->first.c_str(), it->second.lastcheckedrev, headrev);
- if (m_hMainDlg)
- {
- _stprintf_s(infotextbuf, 1024, _T("getting log for %s"), it->first.c_str());
- @@ -750,7 +786,7 @@
- }
- int nNewCommits = 0; // commits without ignored ones
- int nTotalNewCommits = 0; // all commits, including ignored ones
- - if (pSCCS->GetLog(it->second.accurevRepo, it->first, headrev, it->second.lastcheckedrev + 1))
- + if ((headrev <= it->second.lastcheckedrev && gReviewBoard.GetNewReviewsForUrl(it->second.url)) || pSCCS->GetLog(it->second.accurevRepo, it->first, headrev, it->second.lastcheckedrev + 1))
- {
- TRACE(_T("log fetched for %s\n"), it->first.c_str());
- if (!m_bRun)
- @@ -772,112 +808,115 @@
- wstring sPopupText;
- bool hadError = !it->second.error.empty();
- - for (map<svn_revnum_t,SCCSLogEntry>::iterator logit = pSCCS->m_logs.begin(); logit != pSCCS->m_logs.end(); ++logit)
- + if(headrev > it->second.lastcheckedrev)
- {
- - // again, only block for a short time
- - map<wstring,CUrlInfo> * pWrite = m_UrlInfos.GetWriteData();
- - map<wstring,CUrlInfo>::iterator writeIt = pWrite->find(it->first);
- - bool bIgnore = false;
- - bool bEntryExists = false;
- - if (writeIt != pWrite->end())
- + for (map<svn_revnum_t,SCCSLogEntry>::iterator logit = pSCCS->m_logs.begin(); logit != pSCCS->m_logs.end(); ++logit)
- {
- - map<svn_revnum_t,SCCSLogEntry>::iterator existIt = writeIt->second.logentries.find(logit->first);
- - bEntryExists = existIt != writeIt->second.logentries.end();
- - bool readState = false;
- - if (bEntryExists)
- - readState = existIt->second.read;
- - logit->second.read = readState;
- + // again, only block for a short time
- + map<wstring,CUrlInfo> * pWrite = m_UrlInfos.GetWriteData();
- + map<wstring,CUrlInfo>::iterator writeIt = pWrite->find(it->first);
- + bool bIgnore = false;
- + bool bEntryExists = false;
- + if (writeIt != pWrite->end())
- + {
- + map<svn_revnum_t,SCCSLogEntry>::iterator existIt = writeIt->second.logentries.find(logit->first);
- + bEntryExists = existIt != writeIt->second.logentries.end();
- + bool readState = false;
- + if (bEntryExists)
- + readState = existIt->second.read;
- + logit->second.read = readState;
- - writeIt->second.logentries[logit->first] = logit->second;
- + writeIt->second.logentries[logit->first] = logit->second;
- - if (!bEntryExists)
- - {
- - wstring author1 = logit->second.author;
- - std::transform(author1.begin(), author1.end(), author1.begin(), std::tolower);
- + if (!bEntryExists)
- + {
- + wstring author1 = logit->second.author;
- + std::transform(author1.begin(), author1.end(), author1.begin(), std::tolower);
- - if (writeIt->second.includeUsers.size() > 0)
- - {
- - wstring s1 = writeIt->second.includeUsers;
- + if (writeIt->second.includeUsers.size() > 0)
- + {
- + wstring s1 = writeIt->second.includeUsers;
- + std::transform(s1.begin(), s1.end(), s1.begin(), std::tolower);
- + CAppUtils::SearchReplace(s1, _T("\r\n"), _T("\n"));
- + vector<wstring> includeVector = CAppUtils::tokenize_str(s1, _T("\n"));
- + bool bInclude = false;
- + for (vector<wstring>::iterator it = includeVector.begin(); it != includeVector.end(); ++it)
- + {
- + if (author1.compare(*it) == 0)
- + {
- + bInclude = true;
- + break;
- + }
- + }
- + bIgnore = !bInclude;
- + }
- +
- + wstring s1 = writeIt->second.ignoreUsers;
- std::transform(s1.begin(), s1.end(), s1.begin(), std::tolower);
- CAppUtils::SearchReplace(s1, _T("\r\n"), _T("\n"));
- - vector<wstring> includeVector = CAppUtils::tokenize_str(s1, _T("\n"));
- - bool bInclude = false;
- - for (vector<wstring>::iterator it = includeVector.begin(); it != includeVector.end(); ++it)
- + vector<wstring> ignoreVector = CAppUtils::tokenize_str(s1, _T("\n"));
- + for (vector<wstring>::iterator it = ignoreVector.begin(); it != ignoreVector.end(); ++it)
- {
- if (author1.compare(*it) == 0)
- {
- - bInclude = true;
- + bIgnore = true;
- break;
- }
- }
- - bIgnore = !bInclude;
- - }
- -
- - wstring s1 = writeIt->second.ignoreUsers;
- - std::transform(s1.begin(), s1.end(), s1.begin(), std::tolower);
- - CAppUtils::SearchReplace(s1, _T("\r\n"), _T("\n"));
- - vector<wstring> ignoreVector = CAppUtils::tokenize_str(s1, _T("\n"));
- - for (vector<wstring>::iterator it = ignoreVector.begin(); it != ignoreVector.end(); ++it)
- - {
- - if (author1.compare(*it) == 0)
- + nTotalNewCommits++;
- + if (!bIgnore)
- {
- - bIgnore = true;
- - break;
- + bNewEntries = true;
- + nNewCommits++;
- }
- + else
- + // set own commit as already read
- + writeIt->second.logentries[logit->first].read = true;
- }
- - nTotalNewCommits++;
- - if (!bIgnore)
- - {
- - bNewEntries = true;
- - nNewCommits++;
- - }
- - else
- - // set own commit as already read
- - writeIt->second.logentries[logit->first].read = true;
- + writeIt->second.error.clear();
- }
- - writeIt->second.error.clear();
- - }
- - bNeedsSaving = true;
- - m_UrlInfos.ReleaseWriteData();
- - if (!m_bRun)
- - continue;
- - // popup info text
- - if ((!bIgnore)&&(!bEntryExists))
- - {
- - if (!sPopupText.empty())
- - sPopupText += _T(", ");
- - sPopupText += logit->second.author;
- - }
- - if ((!it->second.disallowdiffs)&&(it->second.fetchdiffs))
- - {
- - TCHAR buf[4096];
- - // first, find a name where to store the diff for that revision
- - _stprintf_s(buf, 4096, _T("%s_%ld.diff"), it->second.name.c_str(), logit->first);
- - wstring diffFileName = CAppUtils::GetAppDataDir();
- - diffFileName += _T("/");
- - diffFileName += wstring(buf);
- - // do we already have that diff?
- - if (!PathFileExists(diffFileName.c_str()))
- + bNeedsSaving = true;
- + m_UrlInfos.ReleaseWriteData();
- + if (!m_bRun)
- + continue;
- + // popup info text
- + if ((!bIgnore)&&(!bEntryExists))
- {
- - // get the diff
- - if (m_hMainDlg)
- + if (!sPopupText.empty())
- + sPopupText += _T(", ");
- + sPopupText += logit->second.author;
- + }
- + if ((!it->second.disallowdiffs)&&(it->second.fetchdiffs))
- + {
- + TCHAR buf[4096];
- + // first, find a name where to store the diff for that revision
- + _stprintf_s(buf, 4096, _T("%s_%ld.diff"), it->second.name.c_str(), logit->first);
- + wstring diffFileName = CAppUtils::GetAppDataDir();
- + diffFileName += _T("/");
- + diffFileName += wstring(buf);
- + // do we already have that diff?
- + if (!PathFileExists(diffFileName.c_str()))
- {
- - _stprintf_s(infotextbuf, 1024, _T("getting diff for %s, revision %ld"), it->first.c_str(), logit->first);
- - SendMessage(*this, COMMITMONITOR_INFOTEXT, 0, (LPARAM)infotextbuf);
- + // get the diff
- + if (m_hMainDlg)
- + {
- + _stprintf_s(infotextbuf, 1024, _T("getting diff for %s, revision %ld"), it->first.c_str(), logit->first);
- + SendMessage(*this, COMMITMONITOR_INFOTEXT, 0, (LPARAM)infotextbuf);
- + }
- + if (!pSCCS->Diff(it->first, logit->first, logit->first-1, logit->first, true, true, false, wstring(), false, diffFileName, wstring()))
- + {
- + TRACE(_T("Diff not fetched for %s, revision %ld because of an error\n"), it->first.c_str(), logit->first);
- + DeleteFile(diffFileName.c_str());
- + }
- + else
- + TRACE(_T("Diff fetched for %s, revision %ld\n"), it->first.c_str(), logit->first);
- + if (!m_bRun)
- + break;
- }
- - if (!pSCCS->Diff(it->first, logit->first, logit->first-1, logit->first, true, true, false, wstring(), false, diffFileName, wstring()))
- - {
- - TRACE(_T("Diff not fetched for %s, revision %ld because of an error\n"), it->first.c_str(), logit->first);
- - DeleteFile(diffFileName.c_str());
- - }
- - else
- - TRACE(_T("Diff fetched for %s, revision %ld\n"), it->first.c_str(), logit->first);
- - if (!m_bRun)
- - break;
- }
- }
- }
- - if ((it->second.lastcheckedrobots + (60*60*24*2)) < currenttime)
- + if ((headrev > it->second.lastcheckedrev) && (it->second.lastcheckedrobots + (60*60*24*2)) < currenttime)
- {
- wstring sRobotsURL = it->first;
- sRobotsURL += _T("/svnrobots.txt");
- @@ -984,7 +1023,8 @@
- m_UrlInfos.ReleaseWriteData();
- }
- // prepare notification strings
- - if ((bNewEntries)||(!hadError && !it->second.error.empty()))
- + int nNewReviews = gReviewBoard.GetNewReviewsForUrl(it->second.url);
- + if ((nNewReviews > 0)||(bNewEntries)||(!hadError && !it->second.error.empty()))
- {
- popupData data;
- TCHAR sTitle[1024] = {0};
- @@ -996,10 +1036,31 @@
- else
- {
- data.sProject = it->second.name;
- - if (nNewCommits == 1)
- - _stprintf_s(sTitle, 1024, _T("%s\nhas %d new commit"), it->second.name.c_str(), nNewCommits);
- - else
- - _stprintf_s(sTitle, 1024, _T("%s\nhas %d new commits"), it->second.name.c_str(), nNewCommits);
- + if (nNewCommits == 0)
- + {
- + if(nNewReviews == 1)
- + _stprintf_s(sTitle, 1024, _T("%s\nhas %d new review"), it->second.name.c_str(), nNewReviews);
- + else
- + _stprintf_s(sTitle, 1024, _T("%s\nhas %d new reviews"), it->second.name.c_str(), nNewReviews);
- + }
- + else if (nNewCommits == 1)
- + {
- + if(nNewReviews == 0)
- + _stprintf_s(sTitle, 1024, _T("%s\nhas %d new commit"), it->second.name.c_str(), nNewCommits);
- + else if(nNewReviews == 1)
- + _stprintf_s(sTitle, 1024, _T("%s\nhas %d new commit, %d new review"), it->second.name.c_str(), nNewCommits, nNewReviews);
- + else
- + _stprintf_s(sTitle, 1024, _T("%s\nhas %d new commit, %d new reviews"), it->second.name.c_str(), nNewCommits, nNewReviews);
- + }
- + else
- + {
- + if(nNewReviews == 0)
- + _stprintf_s(sTitle, 1024, _T("%s\nhas %d new commits"), it->second.name.c_str(), nNewCommits);
- + else if(nNewReviews == 1)
- + _stprintf_s(sTitle, 1024, _T("%s\nhas %d new commits, %d new review"), it->second.name.c_str(), nNewCommits, nNewReviews);
- + else
- + _stprintf_s(sTitle, 1024, _T("%s\nhas %d new commits, %d new reviews"), it->second.name.c_str(), nNewCommits, nNewReviews);
- + }
- }
- data.sText = sPopupText;
- data.sTitle = wstring(sTitle);
- Index: src/Http.cpp
- ===================================================================
- --- src/Http.cpp (revision 0)
- +++ src/Http.cpp (revision 0)
- @@ -0,0 +1,112 @@
- +#include "stdafx.h"
- +#include "Http.h"
- +
- +#pragma warning( push )
- +#pragma warning( disable: 4244 )
- +#include "Poco/Net/HTTPClientSession.h"
- +#include "Poco/Net/HTTPRequest.h"
- +#include "Poco/Net/HTTPResponse.h"
- +#include "Poco/StreamCopier.h"
- +#include "Poco/Path.h"
- +#include "Poco/URI.h"
- +#include "Poco/Exception.h"
- +#pragma warning( pop )
- +#include <string>
- +#include <sstream>
- +
- +using Poco::Net::HTTPClientSession;
- +using Poco::Net::HTTPRequest;
- +using Poco::Net::HTTPResponse;
- +using Poco::Net::HTTPMessage;
- +using Poco::StreamCopier;
- +using Poco::Path;
- +using Poco::URI;
- +using Poco::Exception;
- +
- +using namespace std;
- +
- +
- +Http::Http() : inited(false)
- +{
- +}
- +
- +Http::~Http()
- +{
- + if(inited)
- + {
- + }
- +}
- +
- +bool Http::Init(const string& host)
- +{
- + string url = "http://";
- + url += host;
- + url += "/";
- + URI uri(url);
- + std::string path(uri.getPathAndQuery());
- + if (path.empty()) path = "/";
- +
- +
- + session.setHost(uri.getHost());
- + session.setPort(uri.getPort());
- + inited = true;
- + return true;
- +}
- +
- +void Http::GetPageText(const string& path, stringstream& sstrm)
- +{
- + if(!inited)
- + return;
- + HTTPRequest req(HTTPRequest::HTTP_GET, path, HTTPMessage::HTTP_1_1);
- + req.set("Accept","text/x-patch");
- + session.sendRequest(req);
- + HTTPResponse res;
- + std::istream& rs = session.receiveResponse(res);
- + StreamCopier::copyStream(rs, sstrm);
- +}
- +
- +void Http::GetPageXml(const string& path, stringstream& sstrm)
- +{
- + if(!inited)
- + return;
- + HTTPRequest req(HTTPRequest::HTTP_GET, path, HTTPMessage::HTTP_1_1);
- + req.set("Accept","application/xml");
- + session.sendRequest(req);
- + HTTPResponse res;
- + std::istream& rs = session.receiveResponse(res);
- + StreamCopier::copyStream(rs, sstrm);
- +}
- +
- +void Http::GetPageXml(const string& path, string& str)
- +{
- + stringstream sstrm;
- + GetPageXml(path,sstrm);
- + str = sstrm.str();
- +}
- +
- +void Http::GetPageText(const string& path, string& str)
- +{
- + stringstream sstrm;
- + GetPageText(path,sstrm);
- + str = sstrm.str();
- +}
- +
- +void Http::GetPageXml(const string& path, char *& buf, int& len)
- +{
- + string str;
- + GetPageXml(path,str);
- + len = str.length();
- + buf = new char[len+1];
- + memcpy(buf,str.c_str(),len * sizeof(char));
- + buf[len]=0;
- +}
- +
- +void Http::GetPageText(const std::string& path, char *& buf, int& len)
- +{
- + string str;
- + GetPageText(path,str);
- + len = str.length();
- + buf = new char[len+1];
- + memcpy(buf,str.c_str(),len * sizeof(char));
- + buf[len]=0;
- +}
- Index: src/Http.h
- ===================================================================
- --- src/Http.h (revision 0)
- +++ src/Http.h (revision 0)
- @@ -0,0 +1,32 @@
- +#ifndef HTTP_H__
- +#define HTTP_H__
- +
- +#include "stdafx.h"
- +
- +#include "Poco/Net/HTTPClientSession.h"
- +#include <iosfwd>
- +#include "Singleton.h"
- +
- +class Http
- +{
- + friend class Singleton<Http>;
- + Poco::Net::HTTPClientSession session;
- + bool inited;
- +private:
- + Http();
- +public:
- + ~Http();
- + bool Init(const std::string& host);
- + void GetPageXml(const std::string& path, std::stringstream& sstrm);
- + void GetPageText(const std::string& path, std::stringstream& sstrm);
- + void GetPageXml(const std::string& path, std::string& str);
- + void GetPageText(const std::string& path, std::string& str);
- + void GetPageXml(const std::string& path, char *& buf_you_must_delete_this_when_done_with_processing, int& len);
- + void GetPageText(const std::string& path, char *& buf_you_must_delete_this_when_done_with_processing, int& len);
- +};
- +
- +
- +#define gHTTP (*(Singleton<Http>::GetInstance()))
- +#define gHTTP_Cleanup Singleton<Http>::Cleanup()
- +
- +#endif
- Index: src/MainDlg.cpp
- ===================================================================
- --- src/MainDlg.cpp (revision 605)
- +++ src/MainDlg.cpp (working copy)
- @@ -32,6 +32,8 @@
- #include <cctype>
- #include <regex>
- +#include "ReviewBoardXml.h"
- +
- #pragma comment(lib, "uxtheme.lib")
- #define FILTERBOXHEIGHT 20
- @@ -52,6 +54,7 @@
- , m_hImgList(NULL)
- , m_bNewerVersionAvailable(false)
- , m_refreshNeeded(false)
- + , m_commitsradio(true)
- {
- m_hParent = hParent;
- // use the default GUI font, create a copy of it and
- @@ -219,6 +222,11 @@
- m_hListControl = ::GetDlgItem(*this, IDC_MONITOREDURLS);
- m_hLogMsgControl = ::GetDlgItem(*this, IDC_LOGINFO);
- m_hFilterControl = ::GetDlgItem(*this, IDC_FILTERSTRING);
- + m_hCommitsRadio = ::GetDlgItem(*this, IDC_RADIO2);
- + m_hReviewsRadio = ::GetDlgItem(*this, IDC_RADIO3);
- +
- + ::CheckRadioButton(hwndDlg, IDC_RADIO2, IDC_RADIO3, m_commitsradio ? IDC_RADIO2 : IDC_RADIO3);
- +
- ::SendMessage(m_hTreeControl, TVM_SETUNICODEFORMAT, 1, 0);
- SetWindowTheme(m_hListControl, L"Explorer", NULL);
- @@ -278,6 +286,9 @@
- GetClientRect(*this, &rect);
- m_bottommarg = rect.bottom - m_bottommarg;
- + m_radiossize = 160;
- +
- +
- // subclass the tree view control to intercept the WM_SETFOCUS messages
- m_oldTreeWndProc = (WNDPROC)SetWindowLongPtr(m_hTreeControl, GWLP_WNDPROC, (LONG)TreeProc);
- SetWindowLongPtr(m_hTreeControl, GWLP_USERDATA, (LONG)this);
- @@ -446,7 +457,7 @@
- case WM_GETMINMAXINFO:
- {
- MINMAXINFO * mmi = (MINMAXINFO*)lParam;
- - mmi->ptMinTrackSize.x = m_xSliderPos + 100;
- + mmi->ptMinTrackSize.x = m_xSliderPos + 265;
- mmi->ptMinTrackSize.y = m_ySliderPos + 100;
- return 0;
- }
- @@ -503,7 +514,7 @@
- tv.hParent = FindParentTreeNode(it->first);
- tv.hInsertAfter = TVI_SORT;
- tv.itemex.mask = TVIF_TEXT|TVIF_PARAM|TVIF_STATE|TVIF_IMAGE|TVIF_SELECTEDIMAGE;
- - WCHAR * str = new WCHAR[it->second.name.size()+10];
- + WCHAR * str = new WCHAR[it->second.name.size()+30];
- // find out if there are some unread entries
- int unread = 0;
- for (map<svn_revnum_t,SCCSLogEntry>::const_iterator logit = it->second.logentries.begin(); logit != it->second.logentries.end(); ++logit)
- @@ -520,13 +531,14 @@
- tv.itemex.hItem = directItem;
- tv.itemex.stateMask = TVIS_SELECTED|TVIS_BOLD|TVIF_IMAGE|TVIF_SELECTEDIMAGE;
- tv.itemex.pszText = str;
- - tv.itemex.cchTextMax = it->second.name.size()+9;
- + tv.itemex.cchTextMax = it->second.name.size()+29;
- TreeView_GetItem(m_hTreeControl, &tv.itemex);
- wstring sTitle = wstring(str);
- bool bRequiresUpdate = false;
- - if (unread)
- + int unreadreviews = gReviewBoard.GetUnreadReviewsForUrl(it->second.url);
- + if (unread || unreadreviews)
- {
- - _stprintf_s(str, it->second.name.size()+10, _T("%s (%d)"), it->second.name.c_str(), unread);
- + _stprintf_s(str, it->second.name.size()+30, _T("%s (%d + %d)"), it->second.name.c_str(), unread, unreadreviews);
- tv.itemex.state |= TVIS_BOLD;
- tv.itemex.stateMask = TVIS_BOLD;
- }
- @@ -551,7 +563,7 @@
- tv.itemex.iImage = 4;
- tv.itemex.iSelectedImage = 4;
- }
- - else if (unread)
- + else if (unread || unreadreviews)
- {
- bRequiresUpdate = tv.itemex.iImage != 3;
- tv.itemex.iImage = 3;
- @@ -594,9 +606,10 @@
- }
- else
- {
- - if (unread)
- + int unreadreviews = gReviewBoard.GetUnreadReviewsForUrl(it->second.url);
- + if (unread || unreadreviews)
- {
- - _stprintf_s(str, it->second.name.size()+10, _T("%s (%d)"), it->second.name.c_str(), unread);
- + _stprintf_s(str, it->second.name.size()+30, _T("%s (%d + %d)"), it->second.name.c_str(), unread, unreadreviews);
- tv.itemex.state = TVIS_BOLD;
- tv.itemex.stateMask = TVIS_BOLD;
- }
- @@ -619,7 +632,7 @@
- tv.itemex.iImage = 4;
- tv.itemex.iSelectedImage = 4;
- }
- - else if (unread)
- + else if (unread || unreadreviews)
- {
- tv.itemex.iImage = 3;
- tv.itemex.iSelectedImage = 3;
- @@ -820,7 +833,7 @@
- {
- HMENU hMenu = NULL;
- wstring tsvninstalled = CAppUtils::GetTSVNPath();
- - if (tsvninstalled.empty())
- + if (tsvninstalled.empty() || !m_commitsradio)
- hMenu = ::LoadMenu(hResource, MAKEINTRESOURCE(IDR_LISTPOPUP));
- else
- hMenu = ::LoadMenu(hResource, MAKEINTRESOURCE(IDR_LISTPOPUPTSVN));
- @@ -882,48 +895,101 @@
- ListView_GetItem(m_hListControl, &item);
- if (item.state & LVIS_SELECTED)
- {
- - SCCSLogEntry * pLogEntry = (SCCSLogEntry*)item.lParam;
- - if (pLogEntry)
- + if(m_commitsradio)
- {
- - // set the entry as unread
- - if (pLogEntry->read)
- + SCCSLogEntry * pLogEntry = (SCCSLogEntry*)item.lParam;
- + if (pLogEntry)
- {
- - pLogEntry->read = false;
- - // refresh the name of the tree item to indicate the new
- - // number of unread log messages
- - // e.g. instead of 'TortoiseSVN (2)', show now 'TortoiseSVN (3)'
- - if (pRead->find(*(wstring*)itemex.lParam) != pRead->end())
- + // set the entry as unread
- + if (pLogEntry->read)
- {
- - const CUrlInfo * uinfo = &pRead->find(*(wstring*)itemex.lParam)->second;
- - // count the number of unread messages
- - int unread = 0;
- - for (map<svn_revnum_t,SCCSLogEntry>::const_iterator it = uinfo->logentries.begin(); it != uinfo->logentries.end(); ++it)
- + pLogEntry->read = false;
- + // refresh the name of the tree item to indicate the new
- + // number of unread log messages
- + // e.g. instead of 'TortoiseSVN (2)', show now 'TortoiseSVN (3)'
- + if (pRead->find(*(wstring*)itemex.lParam) != pRead->end())
- {
- - if (!it->second.read)
- - unread++;
- + const CUrlInfo * uinfo = &pRead->find(*(wstring*)itemex.lParam)->second;
- + // count the number of unread messages
- + int unread = 0;
- + for (map<svn_revnum_t,SCCSLogEntry>::const_iterator it = uinfo->logentries.begin(); it != uinfo->logentries.end(); ++it)
- + {
- + if (!it->second.read)
- + unread++;
- + }
- + WCHAR * str = new WCHAR[uinfo->name.size()+30];
- + int unreadreviews = gReviewBoard.GetUnreadReviewsForUrl(uinfo->url);
- + if (unread || unreadreviews)
- + {
- + _stprintf_s(str, uinfo->name.size()+30, _T("%s (%d + %d)"), uinfo->name.c_str(), unread, unreadreviews);
- + itemex.state = TVIS_BOLD;
- + itemex.stateMask = TVIS_BOLD;
- + itemex.iImage = 3;
- + itemex.iSelectedImage = 3;
- + }
- + else
- + {
- + _stprintf_s(str, uinfo->name.size()+10, _T("%s"), uinfo->name.c_str());
- + itemex.state = 0;
- + itemex.stateMask = TVIS_BOLD;
- + itemex.iImage = 2;
- + itemex.iSelectedImage = 2;
- + }
- +
- + itemex.pszText = str;
- + itemex.mask = TVIF_TEXT|TVIF_STATE|TVIF_IMAGE|TVIF_SELECTEDIMAGE;
- + m_refreshNeeded = true;
- + TreeView_SetItem(m_hTreeControl, &itemex);
- }
- - WCHAR * str = new WCHAR[uinfo->name.size()+10];
- - if (unread)
- + }
- + }
- + }
- + else
- + {
- + ReviewBoardReview * pLogEntry = (ReviewBoardReview*)item.lParam;
- + if (pLogEntry)
- + {
- + // set the entry as unread
- + if (pLogEntry->read)
- + {
- + gReviewBoard.ReviewSetRead(pLogEntry->reviewid,false);
- + // refresh the name of the tree item to indicate the new
- + // number of unread log messages
- + // e.g. instead of 'TortoiseSVN (2)', show now 'TortoiseSVN (3)'
- + if (pRead->find(*(wstring*)itemex.lParam) != pRead->end())
- {
- - _stprintf_s(str, uinfo->name.size()+10, _T("%s (%d)"), uinfo->name.c_str(), unread);
- - itemex.state = TVIS_BOLD;
- - itemex.stateMask = TVIS_BOLD;
- - itemex.iImage = 3;
- - itemex.iSelectedImage = 3;
- + const CUrlInfo * uinfo = &pRead->find(*(wstring*)itemex.lParam)->second;
- + // count the number of unread messages
- + int unread = 0;
- + for (map<svn_revnum_t,SCCSLogEntry>::const_iterator it = uinfo->logentries.begin(); it != uinfo->logentries.end(); ++it)
- + {
- + if (!it->second.read)
- + unread++;
- + }
- + WCHAR * str = new WCHAR[uinfo->name.size()+30];
- + int unreadreviews = gReviewBoard.GetUnreadReviewsForUrl(uinfo->url);
- + if (unread || unreadreviews)
- + {
- + _stprintf_s(str, uinfo->name.size()+30, _T("%s (%d + %d)"), uinfo->name.c_str(), unread, unreadreviews);
- + itemex.state = TVIS_BOLD;
- + itemex.stateMask = TVIS_BOLD;
- + itemex.iImage = 3;
- + itemex.iSelectedImage = 3;
- + }
- + else
- + {
- + _stprintf_s(str, uinfo->name.size()+10, _T("%s"), uinfo->name.c_str());
- + itemex.state = 0;
- + itemex.stateMask = TVIS_BOLD;
- + itemex.iImage = 2;
- + itemex.iSelectedImage = 2;
- + }
- +
- + itemex.pszText = str;
- + itemex.mask = TVIF_TEXT|TVIF_STATE|TVIF_IMAGE|TVIF_SELECTEDIMAGE;
- + m_refreshNeeded = true;
- + TreeView_SetItem(m_hTreeControl, &itemex);
- }
- - else
- - {
- - _stprintf_s(str, uinfo->name.size()+10, _T("%s"), uinfo->name.c_str());
- - itemex.state = 0;
- - itemex.stateMask = TVIS_BOLD;
- - itemex.iImage = 2;
- - itemex.iSelectedImage = 2;
- - }
- -
- - itemex.pszText = str;
- - itemex.mask = TVIF_TEXT|TVIF_STATE|TVIF_IMAGE|TVIF_SELECTEDIMAGE;
- - m_refreshNeeded = true;
- - TreeView_SetItem(m_hTreeControl, &itemex);
- }
- }
- }
- @@ -1094,13 +1160,36 @@
- if (pRead->find(*(wstring*)itemex.lParam) != pRead->end())
- {
- const CUrlInfo * info = &pRead->find(*(wstring*)itemex.lParam)->second;
- - if ((info)&&(!info->webviewer.empty()))
- + if (!m_commitsradio || ((info)&&(!info->webviewer.empty())))
- {
- // replace "%revision" with the new HEAD revision
- wstring tag(_T("%revision"));
- wstring commandline = info->webviewer;
- + wstring reviewurl;
- + if(!m_commitsradio)
- + {
- + // find the revision
- + LVITEM item = {0};
- + int nItemCount = ListView_GetItemCount(m_hListControl);
- + for (int i=0; i<nItemCount; ++i)
- + {
- + item.mask = LVIF_PARAM|LVIF_STATE;
- + item.stateMask = LVIS_SELECTED;
- + item.iItem = i;
- + ListView_GetItem(m_hListControl, &item);
- + if (item.state & LVIS_SELECTED)
- + {
- + ReviewBoardReview * pLogEntry = (ReviewBoardReview*)item.lParam;
- + if (pLogEntry)
- + {
- + reviewurl = pLogEntry->Url();
- + break;
- + }
- + }
- + }
- + }
- wstring::iterator it_begin = search(commandline.begin(), commandline.end(), tag.begin(), tag.end());
- - if (it_begin != commandline.end())
- + if (m_commitsradio && it_begin != commandline.end())
- {
- // find the revision
- LVITEM item = {0};
- @@ -1143,8 +1232,19 @@
- wstring::iterator it_end= it_begin + tag.size();
- commandline.replace(it_begin, it_end, info->name);
- }
- - if (!commandline.empty())
- + if (!m_commitsradio && !reviewurl.empty())
- {
- + tag = _T("api/review-requests");
- + it_begin = search(reviewurl.begin(), reviewurl.end(), tag.begin(), tag.end());
- + if (it_begin != reviewurl.end())
- + {
- + wstring::iterator it_end= it_begin + tag.size();
- + reviewurl.replace(it_begin, it_end, TEXT("r"));
- + }
- + ShellExecute(*this, _T("open"), reviewurl.c_str(), NULL, NULL, SW_SHOWNORMAL);
- + }
- + else if (!commandline.empty())
- + {
- ShellExecute(*this, _T("open"), commandline.c_str(), NULL, NULL, SW_SHOWNORMAL);
- }
- }
- @@ -1168,12 +1268,15 @@
- {
- dlg.SetInfo(&pRead->find(*(wstring*)itemex.lParam)->second);
- wstring origurl = dlg.GetInfo()->url;
- + dlg.SetReviewMonitored(gReviewBoard.IsUrlMonitored(origurl));
- if (id == ID_POPUP_ADDPROJECTWITHTEMPLATE)
- dlg.ClearForTemplate();
- m_pURLInfos->ReleaseReadOnlyData();
- if (dlg.DoModal(hResource, IDD_URLCONFIG, *this) == IDOK)
- {
- CUrlInfo * inf = dlg.GetInfo();
- + bool monitor = dlg.GetReviewMonitored();
- + bool needsaverev = false;
- if ((inf)&&inf->name.size())
- {
- inf->errNr = 0;
- @@ -1182,9 +1285,25 @@
- if ((inf) && (inf->url.size()) && ((origurl.compare(inf->url)) || (id == ID_MAIN_EDIT)))
- {
- if (id == ID_MAIN_EDIT)
- + {
- pWrite->erase(*(wstring*)itemex.lParam);
- + gReviewBoard.RemoveBranchToMonitor(origurl);
- + needsaverev = true;
- + }
- (*pWrite)[inf->url] = *inf;
- }
- + if(monitor && !gReviewBoard.IsUrlMonitored(inf->url))
- + {
- + gReviewBoard.AddBranchToMonitor(inf->url);
- + needsaverev = true;
- + }
- + else if(!monitor && gReviewBoard.IsUrlMonitored(inf->url))
- + {
- + gReviewBoard.RemoveBranchToMonitor(inf->url);
- + needsaverev = true;
- + }
- + if(needsaverev)
- + gReviewBoard.Save();
- m_pURLInfos->Save();
- m_pURLInfos->ReleaseWriteData();
- RefreshURLTree(false);
- @@ -1291,52 +1410,106 @@
- ListView_GetItem(m_hListControl, &item);
- if (item.state & LVIS_SELECTED)
- {
- - SCCSLogEntry * pLogEntry = (SCCSLogEntry*)item.lParam;
- - if (pLogEntry)
- + if(m_commitsradio)
- {
- - // get the info to put on the clipboard
- - _stprintf_s(tempBuf, 1024, _T("Revision: %ld\nAuthor: %s\nDate: %s\nMessage:\n"),
- - pLogEntry->revision,
- - pLogEntry->author.c_str(),
- - CAppUtils::ConvertDate(pLogEntry->date).c_str());
- - sClipboardData += tempBuf;
- - sClipboardData += pLogEntry->message;
- - sClipboardData += _T("\n-------------------------------\n");
- - // now add all changed paths, one path per line
- - for (map<std::wstring, SCCSLogChangedPaths>::const_iterator it = pLogEntry->m_changedPaths.begin(); it != pLogEntry->m_changedPaths.end(); ++it)
- + SCCSLogEntry * pLogEntry = (SCCSLogEntry*)item.lParam;
- + if (pLogEntry)
- {
- - // action
- - sClipboardData += it->second.action;
- - bool mods = false;
- - if ((it->second.text_modified == svn_tristate_true)||(it->second.props_modified == svn_tristate_true))
- + // get the info to put on the clipboard
- + _stprintf_s(tempBuf, 1024, _T("Revision: %ld\nAuthor: %s\nDate: %s\nMessage:\n"),
- + pLogEntry->revision,
- + pLogEntry->author.c_str(),
- + CAppUtils::ConvertDate(pLogEntry->date).c_str());
- + sClipboardData += tempBuf;
- + sClipboardData += pLogEntry->message;
- + sClipboardData += _T("\n-------------------------------\n");
- + // now add all changed paths, one path per line
- + for (map<std::wstring, SCCSLogChangedPaths>::const_iterator it = pLogEntry->m_changedPaths.begin(); it != pLogEntry->m_changedPaths.end(); ++it)
- {
- - mods = true;
- + // action
- + sClipboardData += it->second.action;
- + bool mods = false;
- + if ((it->second.text_modified == svn_tristate_true)||(it->second.props_modified == svn_tristate_true))
- + {
- + mods = true;
- + }
- + if (mods)
- + sClipboardData += L"(";
- + if (it->second.text_modified == svn_tristate_true)
- + sClipboardData += L"T";
- + else if (mods)
- + sClipboardData += L" ";
- + if (it->second.props_modified == svn_tristate_true)
- + sClipboardData += L"P";
- + else if (mods)
- + sClipboardData += L" ";
- + if (mods)
- + sClipboardData += L")";
- + sClipboardData += _T(" : ");
- + sClipboardData += it->first;
- + sClipboardData += _T(" ");
- + if (!it->second.copyfrom_path.empty())
- + {
- + sClipboardData += _T("(copied from: ");
- + sClipboardData += it->second.copyfrom_path;
- + sClipboardData += _T(", revision ");
- + _stprintf_s(tempBuf, 1024, _T("%ld)\n"), it->second.copyfrom_revision);
- + sClipboardData += wstring(tempBuf);
- + }
- + else
- + sClipboardData += _T("\n\n");
- }
- - if (mods)
- - sClipboardData += L"(";
- - if (it->second.text_modified == svn_tristate_true)
- - sClipboardData += L"T";
- - else if (mods)
- - sClipboardData += L" ";
- - if (it->second.props_modified == svn_tristate_true)
- - sClipboardData += L"P";
- - else if (mods)
- - sClipboardData += L" ";
- - if (mods)
- - sClipboardData += L")";
- - sClipboardData += _T(" : ");
- - sClipboardData += it->first;
- - sClipboardData += _T(" ");
- - if (!it->second.copyfrom_path.empty())
- + }
- + }
- + else
- + {
- + ReviewBoardReview * pLogEntry = (ReviewBoardReview*)item.lParam;
- + if (pLogEntry)
- + {
- + // get the info to put on the clipboard
- + _stprintf_s(tempBuf, 1024, _T("Review id: %s\nAuthor: %s\nDate: %s\nMessage:\n"),
- + pLogEntry->Reviewid().c_str(),
- + pLogEntry->Author().c_str(),
- + pLogEntry->Date().c_str());
- + sClipboardData += tempBuf;
- + sClipboardData += pLogEntry->Message();
- + sClipboardData += _T("\n-------------------------------\n");
- +/* // now add all changed paths, one path per line
- + for (map<std::wstring, SCCSLogChangedPaths>::const_iterator it = pLogEntry->m_changedPaths.begin(); it != pLogEntry->m_changedPaths.end(); ++it)
- {
- - sClipboardData += _T("(copied from: ");
- - sClipboardData += it->second.copyfrom_path;
- - sClipboardData += _T(", revision ");
- - _stprintf_s(tempBuf, 1024, _T("%ld)\n"), it->second.copyfrom_revision);
- - sClipboardData += wstring(tempBuf);
- - }
- - else
- - sClipboardData += _T("\n\n");
- + // action
- + sClipboardData += it->second.action;
- + bool mods = false;
- + if ((it->second.text_modified == svn_tristate_true)||(it->second.props_modified == svn_tristate_true))
- + {
- + mods = true;
- + }
- + if (mods)
- + sClipboardData += L"(";
- + if (it->second.text_modified == svn_tristate_true)
- + sClipboardData += L"T";
- + else if (mods)
- + sClipboardData += L" ";
- + if (it->second.props_modified == svn_tristate_true)
- + sClipboardData += L"P";
- + else if (mods)
- + sClipboardData += L" ";
- + if (mods)
- + sClipboardData += L")";
- + sClipboardData += _T(" : ");
- + sClipboardData += it->first;
- + sClipboardData += _T(" ");
- + if (!it->second.copyfrom_path.empty())
- + {
- + sClipboardData += _T("(copied from: ");
- + sClipboardData += it->second.copyfrom_path;
- + sClipboardData += _T(", revision ");
- + _stprintf_s(tempBuf, 1024, _T("%ld)\n"), it->second.copyfrom_revision);
- + sClipboardData += wstring(tempBuf);
- + }
- + else
- + sClipboardData += _T("\n\n");
- + }*/
- }
- }
- }
- @@ -1391,6 +1564,13 @@
- }
- }
- break;
- + case IDC_RADIO2:
- + case IDC_RADIO3:
- + {
- + m_commitsradio = !m_commitsradio;
- + TreeItemSelected(m_hTreeControl, TreeView_GetSelection(m_hTreeControl));
- + }
- + break;
- default:
- return 0;
- }
- @@ -1447,222 +1627,298 @@
- ListView_GetItem(m_hListControl, &item);
- if (item.state & LVIS_SELECTED)
- {
- - SCCSLogEntry * pLogEntry = (SCCSLogEntry*)item.lParam;
- + if(m_commitsradio)
- + {
- + SCCSLogEntry * pLogEntry = (SCCSLogEntry*)item.lParam;
- - // Switch how the diff is done in SVN / Accurev
- - switch(pUrlInfo->sccs) {
- - default:
- - case CUrlInfo::SCCS_SVN:
- - {
- - // find the diff name
- - const CUrlInfo * pInfo = &pRead->find(*(wstring*)itemex.lParam)->second;
- - // in case the project name has 'path' chars in it, we have to remove those first
- - _stprintf_s(buf, 4096, _T("%s_%ld.diff"), CAppUtils::ConvertName(pInfo->name).c_str(), pLogEntry->revision);
- - wstring diffFileName = CAppUtils::GetDataDir();
- - diffFileName += _T("\\");
- - diffFileName += wstring(buf);
- - // construct a title for the diff viewer
- - _stprintf_s(buf, 4096, _T("%s, revision %ld"), pInfo->name.c_str(), pLogEntry->revision);
- - wstring title = wstring(buf);
- - // start the diff viewer
- - wstring cmd;
- - wstring tsvninstalled = CAppUtils::GetTSVNPath();
- - wstring sVer = CAppUtils::GetVersionStringFromExe(tsvninstalled.c_str());
- - if ((bUseTSVN)&&(!tsvninstalled.empty())&&(_tstoi(sVer.substr(3, 4).c_str()) > 4))
- - {
- - // yes, we have TSVN installed
- - // call TortoiseProc to do the diff for us
- - cmd = _T("\"");
- - cmd += wstring(tsvninstalled);
- - cmd += _T("\" /command:diff /path:\"");
- - cmd += pInfo->url;
- - cmd += _T("\" /startrev:");
- + // Switch how the diff is done in SVN / Accurev
- + switch(pUrlInfo->sccs) {
- + default:
- + case CUrlInfo::SCCS_SVN:
- + {
- + // find the diff name
- + const CUrlInfo * pInfo = &pRead->find(*(wstring*)itemex.lParam)->second;
- + // in case the project name has 'path' chars in it, we have to remove those first
- + _stprintf_s(buf, 4096, _T("%s_%ld.diff"), CAppUtils::ConvertName(pInfo->name).c_str(), pLogEntry->revision);
- + wstring diffFileName = CAppUtils::GetDataDir();
- + diffFileName += _T("\\");
- + diffFileName += wstring(buf);
- + // construct a title for the diff viewer
- + _stprintf_s(buf, 4096, _T("%s, revision %ld"), pInfo->name.c_str(), pLogEntry->revision);
- + wstring title = wstring(buf);
- + // start the diff viewer
- + wstring cmd;
- + wstring tsvninstalled = CAppUtils::GetTSVNPath();
- + wstring sVer = CAppUtils::GetVersionStringFromExe(tsvninstalled.c_str());
- + if ((bUseTSVN)&&(!tsvninstalled.empty())&&(_tstoi(sVer.substr(3, 4).c_str()) > 4))
- + {
- + // yes, we have TSVN installed
- + // call TortoiseProc to do the diff for us
- + cmd = _T("\"");
- + cmd += wstring(tsvninstalled);
- + cmd += _T("\" /command:diff /path:\"");
- + cmd += pInfo->url;
- + cmd += _T("\" /startrev:");
- - TCHAR numBuf[100] = {0};
- - _stprintf_s(numBuf, 100, _T("%ld"), pLogEntry->revision-1);
- - cmd += numBuf;
- - cmd += _T(" /endrev:");
- - _stprintf_s(numBuf, 100, _T("%ld"), pLogEntry->revision);
- - cmd += numBuf;
- - CAppUtils::LaunchApplication(cmd);
- - }
- - else
- - {
- - TCHAR apppath[4096];
- - GetModuleFileName(NULL, apppath, 4096);
- - CRegStdString diffViewer = CRegStdString(_T("Software\\CommitMonitor\\DiffViewer"));
- - if (wstring(diffViewer).empty())
- - {
- - cmd = apppath;
- - cmd += _T(" /patchfile:\"");
- + TCHAR numBuf[100] = {0};
- + _stprintf_s(numBuf, 100, _T("%ld"), pLogEntry->revision-1);
- + cmd += numBuf;
- + cmd += _T(" /endrev:");
- + _stprintf_s(numBuf, 100, _T("%ld"), pLogEntry->revision);
- + cmd += numBuf;
- + CAppUtils::LaunchApplication(cmd);
- }
- else
- {
- - cmd = (wstring)diffViewer;
- - cmd += _T(" \"");
- - }
- - cmd += diffFileName;
- - cmd += _T("\"");
- - if (wstring(diffViewer).empty())
- - {
- - cmd += _T(" /title:\"");
- - cmd += title;
- - cmd += _T("\"");
- - }
- - // Check if the diff file exists. If it doesn't, we have to fetch
- - // the diff first
- - if (!PathFileExists(diffFileName.c_str()))
- - {
- - // fetch the diff
- - SVN svn;
- - svn.SetAuthInfo(pInfo->username, pInfo->password);
- - CProgressDlg progDlg;
- - svn.SetAndClearProgressInfo(&progDlg);
- - progDlg.SetTitle(_T("Fetching Diff"));
- - TCHAR dispbuf[MAX_PATH] = {0};
- - _stprintf_s(dispbuf, MAX_PATH, _T("fetching diff of revision %ld"), pLogEntry->revision);
- - progDlg.SetLine(1, dispbuf);
- - progDlg.SetShowProgressBar(false);
- - progDlg.ShowModeless(*this);
- - progDlg.SetLine(1, dispbuf);
- - progDlg.SetProgress(3, 100); // set some dummy progress
- - CRegStdString diffParams = CRegStdString(_T("Software\\CommitMonitor\\DiffParameters"));
- - if (!svn.Diff(pInfo->url, pLogEntry->revision, pLogEntry->revision-1, pLogEntry->revision, true, true, false, diffParams, false, diffFileName, wstring()))
- + TCHAR apppath[4096];
- + GetModuleFileName(NULL, apppath, 4096);
- + CRegStdString diffViewer = CRegStdString(_T("Software\\CommitMonitor\\DiffViewer"));
- + if (wstring(diffViewer).empty())
- {
- - progDlg.Stop();
- - if (svn.Err->apr_err != SVN_ERR_CANCELLED)
- - ::MessageBox(*this, svn.GetLastErrorMsg().c_str(), _T("CommitMonitor"), MB_ICONERROR);
- - DeleteFile(diffFileName.c_str());
- + cmd = apppath;
- + cmd += _T(" /patchfile:\"");
- }
- else
- {
- - TRACE(_T("Diff fetched for %s, revision %ld\n"), pInfo->url.c_str(), pLogEntry->revision);
- - progDlg.Stop();
- + cmd = (wstring)diffViewer;
- + cmd += _T(" \"");
- }
- + cmd += diffFileName;
- + cmd += _T("\"");
- + if (wstring(diffViewer).empty())
- + {
- + cmd += _T(" /title:\"");
- + cmd += title;
- + cmd += _T("\"");
- + }
- + // Check if the diff file exists. If it doesn't, we have to fetch
- + // the diff first
- + if (!PathFileExists(diffFileName.c_str()))
- + {
- + // fetch the diff
- + SVN svn;
- + svn.SetAuthInfo(pInfo->username, pInfo->password);
- + CProgressDlg progDlg;
- + svn.SetAndClearProgressInfo(&progDlg);
- + progDlg.SetTitle(_T("Fetching Diff"));
- + TCHAR dispbuf[MAX_PATH] = {0};
- + _stprintf_s(dispbuf, MAX_PATH, _T("fetching diff of revision %ld"), pLogEntry->revision);
- + progDlg.SetLine(1, dispbuf);
- + progDlg.SetShowProgressBar(false);
- + progDlg.ShowModeless(*this);
- + progDlg.SetLine(1, dispbuf);
- + progDlg.SetProgress(3, 100); // set some dummy progress
- + CRegStdString diffParams = CRegStdString(_T("Software\\CommitMonitor\\DiffParameters"));
- + if (!svn.Diff(pInfo->url, pLogEntry->revision, pLogEntry->revision-1, pLogEntry->revision, true, true, false, diffParams, false, diffFileName, wstring()))
- + {
- + progDlg.Stop();
- + if (svn.Err->apr_err != SVN_ERR_CANCELLED)
- + ::MessageBox(*this, svn.GetLastErrorMsg().c_str(), _T("CommitMonitor"), MB_ICONERROR);
- + DeleteFile(diffFileName.c_str());
- + }
- + else
- + {
- + TRACE(_T("Diff fetched for %s, revision %ld\n"), pInfo->url.c_str(), pLogEntry->revision);
- + progDlg.Stop();
- + }
- + }
- + if (PathFileExists(diffFileName.c_str()))
- + CAppUtils::LaunchApplication(cmd);
- }
- - if (PathFileExists(diffFileName.c_str()))
- - CAppUtils::LaunchApplication(cmd);
- - }
- - }
- - break;
- + }
- + break;
- - case CUrlInfo::SCCS_ACCUREV:
- - {
- - /* Accurev 'diff' cannot be used as it mutex locks itself to only allow diffing of one
- - * file at a time... how typical. Therefore we 'pop' (get copies) of the correct versions
- - * of each file and then diff the directories :)
- - * TODO: Somehow hold onto and delete the temporary dirs when commit monitor is closed */
- - CRegStdString accurevExe = CRegStdString(_T("Software\\CommitMonitor\\AccurevExe"));
- + case CUrlInfo::SCCS_ACCUREV:
- + {
- + /* Accurev 'diff' cannot be used as it mutex locks itself to only allow diffing of one
- + * file at a time... how typical. Therefore we 'pop' (get copies) of the correct versions
- + * of each file and then diff the directories :)
- + * TODO: Somehow hold onto and delete the temporary dirs when commit monitor is closed */
- + CRegStdString accurevExe = CRegStdString(_T("Software\\CommitMonitor\\AccurevExe"));
- - wchar_t transactionNo[64];
- - _itow_s(pLogEntry->revision, transactionNo, 10);
- + wchar_t transactionNo[64];
- + _itow_s(pLogEntry->revision, transactionNo, 10);
- - wstring uuid;
- - CAppUtils::CreateUUIDString(uuid);
- + wstring uuid;
- + CAppUtils::CreateUUIDString(uuid);
- - wstring newTempPath = wstring(origTempPath);
- - newTempPath.append(_T("\\"));
- - newTempPath.append(uuid);
- - wstring sLatestRev(transactionNo);
- - wstring sBasisRev = _T("BASIS");
- - wstring latestDir(newTempPath + _T("\\") + sLatestRev);
- - wstring basisDir(newTempPath + _T("\\") + sBasisRev);
- - CreateDirectory(newTempPath.c_str(), NULL);
- - CreateDirectory(latestDir.c_str(), NULL);
- - CreateDirectory(basisDir.c_str(), NULL);
- + wstring newTempPath = wstring(origTempPath);
- + newTempPath.append(_T("\\"));
- + newTempPath.append(uuid);
- + wstring sLatestRev(transactionNo);
- + wstring sBasisRev = _T("BASIS");
- + wstring latestDir(newTempPath + _T("\\") + sLatestRev);
- + wstring basisDir(newTempPath + _T("\\") + sBasisRev);
- + CreateDirectory(newTempPath.c_str(), NULL);
- + CreateDirectory(latestDir.c_str(), NULL);
- + CreateDirectory(basisDir.c_str(), NULL);
- - // For each file that should be diffed
- - for (map<std::wstring,SCCSLogChangedPaths>::const_iterator it = pLogEntry->m_changedPaths.begin(); it != pLogEntry->m_changedPaths.end(); ++it)
- - {
- - // Parse the file and file revision from the stored URL
- - wstring rawPath = it->first;
- + // For each file that should be diffed
- + for (map<std::wstring,SCCSLogChangedPaths>::const_iterator it = pLogEntry->m_changedPaths.begin(); it != pLogEntry->m_changedPaths.end(); ++it)
- + {
- + // Parse the file and file revision from the stored URL
- + wstring rawPath = it->first;
- - int lastBracket = rawPath.rfind(L" (");
- - rawPath.erase(lastBracket, wstring::npos);
- - int lastForwardSlash = rawPath.rfind(L"/");
- - wstring sLatestAccuRevision(rawPath);
- - sLatestAccuRevision.erase(0, lastForwardSlash+1);
- - int iAccuRevision = _wtoi(sLatestAccuRevision.c_str());
- - wchar_t basisRevisionNo[64];
- - _itow_s(iAccuRevision-1, basisRevisionNo, 10);
- - wstring sBasisAccuRevision(basisRevisionNo);
- + int lastBracket = rawPath.rfind(L" (");
- + rawPath.erase(lastBracket, wstring::npos);
- + int lastForwardSlash = rawPath.rfind(L"/");
- + wstring sLatestAccuRevision(rawPath);
- + sLatestAccuRevision.erase(0, lastForwardSlash+1);
- + int iAccuRevision = _wtoi(sLatestAccuRevision.c_str());
- + wchar_t basisRevisionNo[64];
- + _itow_s(iAccuRevision-1, basisRevisionNo, 10);
- + wstring sBasisAccuRevision(basisRevisionNo);
- - wstring finalPath(rawPath);
- - int lastSpace = rawPath.rfind(L" ");
- - finalPath.erase(lastSpace, wstring::npos);
- + wstring finalPath(rawPath);
- + int lastSpace = rawPath.rfind(L" ");
- + finalPath.erase(lastSpace, wstring::npos);
- - // Can't diff unless there is a version to diff against :)
- - if (iAccuRevision >= 1) {
- + // Can't diff unless there is a version to diff against :)
- + if (iAccuRevision >= 1) {
- - // Check out the latest file
- - // Build the accurev command line
- - for (int i=0; i<2; i++) {
- - wstring accurevPopCmd;
- - wstring rev;
- - wstring dir;
- + // Check out the latest file
- + // Build the accurev command line
- + for (int i=0; i<2; i++) {
- + wstring accurevPopCmd;
- + wstring rev;
- + wstring dir;
- - switch (i) {
- - default:
- - case 0:
- - rev = sLatestAccuRevision;
- - dir = latestDir;
- - break;
- - case 1:
- - rev = sBasisAccuRevision;
- - dir = basisDir;
- - break;
- - }
- + switch (i) {
- + default:
- + case 0:
- + rev = sLatestAccuRevision;
- + dir = latestDir;
- + break;
- + case 1:
- + rev = sBasisAccuRevision;
- + dir = basisDir;
- + break;
- + }
- - /* If this is the basis version, and there is none, since the file was added, then break
- - * so we only check out the new version. This will then be shown in the directory compare :) */
- - if ((i == 1) && (iAccuRevision == 1)) break;
- + /* If this is the basis version, and there is none, since the file was added, then break
- + * so we only check out the new version. This will then be shown in the directory compare :) */
- + if ((i == 1) && (iAccuRevision == 1)) break;
- - accurevPopCmd.append(_T("\""));
- - accurevPopCmd.append(wstring(accurevExe));
- - accurevPopCmd.append(_T("\" pop -O -R -v "));
- - accurevPopCmd.append(pUrlInfo->url);
- - accurevPopCmd.append(_T("/"));
- - accurevPopCmd.append(rev);
- - accurevPopCmd.append(_T(" -L \""));
- - accurevPopCmd.append(dir);
- - accurevPopCmd.append(_T("\" \""));
- - accurevPopCmd.append(finalPath);
- - accurevPopCmd.append(_T("\""));
- + accurevPopCmd.append(_T("\""));
- + accurevPopCmd.append(wstring(accurevExe));
- + accurevPopCmd.append(_T("\" pop -O -R -v "));
- + accurevPopCmd.append(pUrlInfo->url);
- + accurevPopCmd.append(_T("/"));
- + accurevPopCmd.append(rev);
- + accurevPopCmd.append(_T(" -L \""));
- + accurevPopCmd.append(dir);
- + accurevPopCmd.append(_T("\" \""));
- + accurevPopCmd.append(finalPath);
- + accurevPopCmd.append(_T("\""));
- - // Run accurev to perform the pop command
- - CAppUtils::LaunchApplication(accurevPopCmd, true, true, true);
- + // Run accurev to perform the pop command
- + CAppUtils::LaunchApplication(accurevPopCmd, true, true, true);
- + }
- +
- + }
- }
- - }
- - }
- + CRegStdString diffCmd = CRegStdString(_T("Software\\CommitMonitor\\AccurevDiffCmd"));
- + wstring finalDiffCmd;
- - CRegStdString diffCmd = CRegStdString(_T("Software\\CommitMonitor\\AccurevDiffCmd"));
- - wstring finalDiffCmd;
- + // Build the final diff command
- + finalDiffCmd.append(wstring(diffCmd));
- - // Build the final diff command
- - finalDiffCmd.append(wstring(diffCmd));
- + // Find and replace "%OLD"
- + int pos = finalDiffCmd.find(_T("%OLD"));
- + finalDiffCmd.replace(pos, 4, sBasisRev, 0, sBasisRev.size());
- - // Find and replace "%OLD"
- - int pos = finalDiffCmd.find(_T("%OLD"));
- - finalDiffCmd.replace(pos, 4, sBasisRev, 0, sBasisRev.size());
- + // Find and replace "%NEW"
- + pos = finalDiffCmd.find(_T("%NEW"));
- + finalDiffCmd.replace(pos, 4, sLatestRev, 0, sLatestRev.size());
- - // Find and replace "%NEW"
- - pos = finalDiffCmd.find(_T("%NEW"));
- - finalDiffCmd.replace(pos, 4, sLatestRev, 0, sLatestRev.size());
- + // Find and replace "%1"
- + pos = finalDiffCmd.find(_T("%1"));
- + finalDiffCmd.replace(pos, 2, basisDir, 0, basisDir.size());
- - // Find and replace "%1"
- - pos = finalDiffCmd.find(_T("%1"));
- - finalDiffCmd.replace(pos, 2, basisDir, 0, basisDir.size());
- + // Find and replace "%2"
- + pos = finalDiffCmd.find(_T("%2"));
- + finalDiffCmd.replace(pos, 2, latestDir, 0, latestDir.size());
- - // Find and replace "%2"
- - pos = finalDiffCmd.find(_T("%2"));
- - finalDiffCmd.replace(pos, 2, latestDir, 0, latestDir.size());
- + // Run accurev to perform the diff command
- + CAppUtils::LaunchApplication(finalDiffCmd, true, false, false);
- + }
- + break;
- + }
- + }
- + else
- + {
- + ReviewBoardReview * pLogEntry = (ReviewBoardReview*)item.lParam;
- +
- + // Switch how the diff is done in SVN / Accurev
- + switch(pUrlInfo->sccs) {
- + default:
- + case CUrlInfo::SCCS_SVN:
- + {
- + // find the diff name
- + const CUrlInfo * pInfo = &pRead->find(*(wstring*)itemex.lParam)->second;
- + // in case the project name has 'path' chars in it, we have to remove those first
- + _stprintf_s(buf, 4096, _T("%s_review_%s.diff"), CAppUtils::ConvertName(pInfo->name).c_str(), pLogEntry->Reviewid().c_str());
- + wstring diffFileName = CAppUtils::GetDataDir();
- + diffFileName += _T("\\");
- + diffFileName += wstring(buf);
- + // construct a title for the diff viewer
- + _stprintf_s(buf, 4096, _T("%s, review id %s"), pInfo->name.c_str(), pLogEntry->Reviewid().c_str());
- + wstring title = wstring(buf);
- + // start the diff viewer
- + wstring cmd;
- - // Run accurev to perform the diff command
- - CAppUtils::LaunchApplication(finalDiffCmd, true, false, false);
- + TCHAR apppath[4096];
- + GetModuleFileName(NULL, apppath, 4096);
- + CRegStdString diffViewer = CRegStdString(_T("Software\\CommitMonitor\\DiffViewer"));
- + if (wstring(diffViewer).empty())
- + {
- + cmd = apppath;
- + cmd += _T(" /patchfile:\"");
- + }
- + else
- + {
- + cmd = (wstring)diffViewer;
- + cmd += _T(" \"");
- + }
- + cmd += diffFileName;
- + cmd += _T("\"");
- + if (wstring(diffViewer).empty())
- + {
- + cmd += _T(" /title:\"");
- + cmd += title;
- + cmd += _T("\"");
- + }
- + // Check if the diff file exists. If it doesn't, we have to fetch
- + // the diff first
- + if (!PathFileExists(diffFileName.c_str()))
- + {
- + // fetch the diff
- + SVN svn;
- + svn.SetAuthInfo(pInfo->username, pInfo->password);
- + CProgressDlg progDlg;
- + svn.SetAndClearProgressInfo(&progDlg);
- + progDlg.SetTitle(_T("Fetching Diff"));
- + TCHAR dispbuf[MAX_PATH] = {0};
- + _stprintf_s(dispbuf, MAX_PATH, _T("fetching diff of review id %s"), pLogEntry->Reviewid().c_str());
- + progDlg.SetLine(1, dispbuf);
- + progDlg.SetShowProgressBar(false);
- + progDlg.ShowModeless(*this);
- + progDlg.SetLine(1, dispbuf);
- + progDlg.SetProgress(3, 100); // set some dummy progress
- + CRegStdString diffParams = CRegStdString(_T("Software\\CommitMonitor\\DiffParameters"));
- + ReviewBoardReviewUnifiedDiff unidiff;
- + unidiff.Open(pLogEntry->reviewid.c_str());
- + unidiff.Save(diffFileName);
- + TRACE(_T("Diff fetched for %s, review id %s\n"), pInfo->url.c_str(), pLogEntry->Reviewid().c_str());
- + progDlg.Stop();
- + }
- + if (PathFileExists(diffFileName.c_str()))
- + CAppUtils::LaunchApplication(cmd);
- + }
- + break;
- }
- - break;
- }
- }
- }
- @@ -1699,7 +1955,7 @@
- tv.hParent = FindParentTreeNode(it->first);
- tv.hInsertAfter = TVI_SORT;
- tv.itemex.mask = TVIF_TEXT|TVIF_PARAM|TVIF_STATE|TVIF_IMAGE|TVIF_SELECTEDIMAGE;
- - WCHAR * str = new WCHAR[it->second.name.size()+10];
- + WCHAR * str = new WCHAR[it->second.name.size()+30];
- // find out if there are some unread entries
- int unread = 0;
- for (map<svn_revnum_t,SCCSLogEntry>::const_iterator logit = it->second.logentries.begin(); logit != it->second.logentries.end(); ++logit)
- @@ -1707,9 +1963,10 @@
- if (!logit->second.read)
- unread++;
- }
- - if (unread)
- + int unreadreviews = gReviewBoard.GetUnreadReviewsForUrl(it->second.url);
- + if (unread || unreadreviews)
- {
- - _stprintf_s(str, it->second.name.size()+10, _T("%s (%d)"), it->second.name.c_str(), unread);
- + _stprintf_s(str, it->second.name.size()+30, _T("%s (%d + %d)"), it->second.name.c_str(), unread, unreadreviews);
- tv.itemex.state = TVIS_BOLD;
- tv.itemex.stateMask = TVIS_BOLD;
- }
- @@ -1747,7 +2004,7 @@
- HTREEITEM hItem = TreeView_InsertItem(m_hTreeControl, &tv);
- if ((!bShowLastUnread)&&(m_lastSelectedProject.compare(it->second.name) == 0))
- tvToSel = hItem;
- - if ((unread)&&(tvToSel == 0))
- + if ((unread || unreadreviews)&&(tvToSel == 0))
- tvToSel = hItem;
- TreeView_Expand(m_hTreeControl, tv.hParent, TVE_EXPAND);
- delete [] str;
- @@ -1955,14 +2212,28 @@
- lvc.mask = LVCF_TEXT;
- lvc.fmt = LVCFMT_LEFT;
- lvc.cx = -1;
- - lvc.pszText = _T("revision");
- - ListView_InsertColumn(m_hListControl, 0, &lvc);
- - lvc.pszText = _T("date");
- - ListView_InsertColumn(m_hListControl, 1, &lvc);
- - lvc.pszText = _T("author");
- - ListView_InsertColumn(m_hListControl, 2, &lvc);
- - lvc.pszText = _T("log message");
- - ListView_InsertColumn(m_hListControl, 3, &lvc);
- + if(m_commitsradio)
- + {
- + lvc.pszText = _T("revision");
- + ListView_InsertColumn(m_hListControl, 0, &lvc);
- + lvc.pszText = _T("date");
- + ListView_InsertColumn(m_hListControl, 1, &lvc);
- + lvc.pszText = _T("author");
- + ListView_InsertColumn(m_hListControl, 2, &lvc);
- + lvc.pszText = _T("log message");
- + ListView_InsertColumn(m_hListControl, 3, &lvc);
- + }
- + else
- + {
- + lvc.pszText = _T("review id");
- + ListView_InsertColumn(m_hListControl, 0, &lvc);
- + lvc.pszText = _T("date");
- + ListView_InsertColumn(m_hListControl, 1, &lvc);
- + lvc.pszText = _T("author");
- + ListView_InsertColumn(m_hListControl, 2, &lvc);
- + lvc.pszText = _T("log message");
- + ListView_InsertColumn(m_hListControl, 3, &lvc);
- + }
- LVITEM item = {0};
- TCHAR buf[1024];
- @@ -1984,99 +2255,203 @@
- delete [] buffer;
- - for (map<svn_revnum_t,SCCSLogEntry>::const_iterator it = info->logentries.begin(); it != info->logentries.end(); ++it)
- + if(m_commitsradio)
- {
- - // only add entries that match the filter string
- - bool addEntry = true;
- - bool useFilter = filterstringlower.size() != 0;
- - bool bUseRegex = (filterstring.size() > 1)&&(filterstring[0] == '\\');
- + for (map<svn_revnum_t,SCCSLogEntry>::const_iterator it = info->logentries.begin(); it != info->logentries.end(); ++it)
- + {
- + // only add entries that match the filter string
- + bool addEntry = true;
- + bool useFilter = filterstringlower.size() != 0;
- + bool bUseRegex = (filterstring.size() > 1)&&(filterstring[0] == '\\');
- - if (useFilter)
- - {
- - if (bUseRegex)
- - {
- - try
- + if (useFilter)
- {
- - const tr1::wregex regCheck(filterstring.substr(1), tr1::regex_constants::icase | tr1::regex_constants::ECMAScript);
- + if (bUseRegex)
- + {
- + try
- + {
- + const tr1::wregex regCheck(filterstring.substr(1), tr1::regex_constants::icase | tr1::regex_constants::ECMAScript);
- - addEntry = tr1::regex_search(it->second.author, regCheck);
- + addEntry = tr1::regex_search(it->second.author, regCheck);
- + if (!addEntry)
- + {
- + addEntry = tr1::regex_search(it->second.message, regCheck);
- + if (!addEntry)
- + {
- + _stprintf_s(buf, 1024, _T("%ld"), it->first);
- + wstring s = wstring(buf);
- + addEntry = tr1::regex_search(s, regCheck);
- + }
- + }
- + }
- + catch (exception)
- + {
- + bUseRegex = false;
- + }
- + if (bNegateFilter)
- + addEntry = !addEntry;
- + }
- + if (!bUseRegex)
- + {
- + // search plain text
- + // note: \Q...\E doesn't seem to work with tr1 - it still
- + // throws an exception if the regex in between is not a valid regex :(
- +
- + wstring s = it->second.author;
- + std::transform(s.begin(), s.end(), s.begin(), std::tolower);
- + addEntry = s.find(filterstringlower) != wstring::npos;
- +
- if (!addEntry)
- {
- - addEntry = tr1::regex_search(it->second.message, regCheck);
- + s = it->second.message;
- + std::transform(s.begin(), s.end(), s.begin(), std::tolower);
- + addEntry = s.find(filterstringlower) != wstring::npos;
- if (!addEntry)
- {
- _stprintf_s(buf, 1024, _T("%ld"), it->first);
- - wstring s = wstring(buf);
- - addEntry = tr1::regex_search(s, regCheck);
- + s = buf;
- + addEntry = s.find(filterstringlower) != wstring::npos;
- }
- }
- + if (bNegateFilter)
- + addEntry = !addEntry;
- }
- - catch (exception)
- + }
- +
- + if (!addEntry)
- + continue;
- +
- + item.mask = LVIF_TEXT|LVIF_PARAM;
- + item.iItem = 0;
- + item.lParam = (LPARAM)&it->second;
- + _stprintf_s(buf, 1024, _T("%ld"), it->first);
- + item.pszText = buf;
- + ListView_InsertItem(m_hListControl, &item);
- + if (it->second.date)
- + _tcscpy_s(buf, 1024, CAppUtils::ConvertDate(it->second.date).c_str());
- + else
- + _tcscpy_s(buf, 1024, _T("(no date)"));
- + ListView_SetItemText(m_hListControl, 0, 1, buf);
- + if (it->second.author.size())
- + _tcscpy_s(buf, 1024, it->second.author.c_str());
- + else
- + _tcscpy_s(buf, 1024, _T("(no author)"));
- + ListView_SetItemText(m_hListControl, 0, 2, buf);
- + wstring msg = it->second.message;
- + std::remove(msg.begin(), msg.end(), '\r');
- + std::replace(msg.begin(), msg.end(), '\n', ' ');
- + std::replace(msg.begin(), msg.end(), '\t', ' ');
- + _tcsncpy_s(buf, 1024, msg.c_str(), 1023);
- + ListView_SetItemText(m_hListControl, 0, 3, buf);
- +
- + if ((iLastUnread < 0)&&(!it->second.read))
- {
- - bUseRegex = false;
- + iLastUnread = 0;
- }
- - if (bNegateFilter)
- - addEntry = !addEntry;
- + if (iLastUnread >= 0)
- + iLastUnread++;
- }
- - if (!bUseRegex)
- + }
- + else
- + {
- + ReviewBoard::WR2Rmap vec;
- + gReviewBoard.GetReviewsForUrl(info->url,vec);
- + gReviewBoard.GetReadLock();
- + for (ReviewBoard::WR2Rmap::const_iterator it = vec.begin(); it != vec.end(); ++it)
- {
- - // search plain text
- - // note: \Q...\E doesn't seem to work with tr1 - it still
- - // throws an exception if the regex in between is not a valid regex :(
- + // only add entries that match the filter string
- + bool addEntry = true;
- + bool useFilter = filterstringlower.size() != 0;
- + bool bUseRegex = (filterstring.size() > 1)&&(filterstring[0] == '\\');
- - wstring s = it->second.author;
- - std::transform(s.begin(), s.end(), s.begin(), std::tolower);
- - addEntry = s.find(filterstringlower) != wstring::npos;
- + if (useFilter)
- + {
- + if (bUseRegex)
- + {
- + try
- + {
- + const tr1::wregex regCheck(filterstring.substr(1), tr1::regex_constants::icase | tr1::regex_constants::ECMAScript);
- - if (!addEntry)
- + addEntry = tr1::regex_search(it->second->Author(), regCheck);
- + if (!addEntry)
- + {
- + addEntry = tr1::regex_search(it->second->Message(), regCheck);
- + if (!addEntry)
- + {
- + _stprintf_s(buf, 1024, _T("%ld"), it->first);
- + wstring s = wstring(buf);
- + addEntry = tr1::regex_search(s, regCheck);
- + }
- + }
- + }
- + catch (exception)
- + {
- + bUseRegex = false;
- + }
- + if (bNegateFilter)
- + addEntry = !addEntry;
- + }
- + if (!bUseRegex)
- {
- - s = it->second.message;
- + // search plain text
- + // note: \Q...\E doesn't seem to work with tr1 - it still
- + // throws an exception if the regex in between is not a valid regex :(
- +
- + wstring s = it->second->Author();
- std::transform(s.begin(), s.end(), s.begin(), std::tolower);
- addEntry = s.find(filterstringlower) != wstring::npos;
- +
- if (!addEntry)
- {
- - _stprintf_s(buf, 1024, _T("%ld"), it->first);
- - s = buf;
- - addEntry = s.find(filterstringlower) != wstring::npos;
- + s = it->second->Message();
- + std::transform(s.begin(), s.end(), s.begin(), std::tolower);
- + addEntry = s.find(filterstringlower) != wstring::npos;
- + if (!addEntry)
- + {
- + _stprintf_s(buf, 1024, _T("%ld"), it->first);
- + s = buf;
- + addEntry = s.find(filterstringlower) != wstring::npos;
- + }
- }
- + if (bNegateFilter)
- + addEntry = !addEntry;
- }
- - if (bNegateFilter)
- - addEntry = !addEntry;
- - }
- - }
- + }
- - if (!addEntry)
- - continue;
- + if (!addEntry)
- + continue;
- - item.mask = LVIF_TEXT|LVIF_PARAM;
- - item.iItem = 0;
- - item.lParam = (LPARAM)&it->second;
- - _stprintf_s(buf, 1024, _T("%ld"), it->first);
- - item.pszText = buf;
- - ListView_InsertItem(m_hListControl, &item);
- - if (it->second.date)
- - _tcscpy_s(buf, 1024, CAppUtils::ConvertDate(it->second.date).c_str());
- - else
- - _tcscpy_s(buf, 1024, _T("(no date)"));
- - ListView_SetItemText(m_hListControl, 0, 1, buf);
- - if (it->second.author.size())
- - _tcscpy_s(buf, 1024, it->second.author.c_str());
- - else
- - _tcscpy_s(buf, 1024, _T("(no author)"));
- - ListView_SetItemText(m_hListControl, 0, 2, buf);
- - wstring msg = it->second.message;
- - std::remove(msg.begin(), msg.end(), '\r');
- - std::replace(msg.begin(), msg.end(), '\n', ' ');
- - std::replace(msg.begin(), msg.end(), '\t', ' ');
- - _tcsncpy_s(buf, 1024, msg.c_str(), 1023);
- - ListView_SetItemText(m_hListControl, 0, 3, buf);
- + item.mask = LVIF_TEXT|LVIF_PARAM;
- + item.iItem = 0;
- + item.lParam = (LPARAM)it->second;
- + _stprintf_s(buf, 1024, _T("%s"), it->first.c_str());
- + item.pszText = buf;
- + ListView_InsertItem(m_hListControl, &item);
- + if (it->second->Date().size())
- + _tcscpy_s(buf, 1024, it->second->Date().c_str());
- + else
- + _tcscpy_s(buf, 1024, _T("(no date)"));
- + ListView_SetItemText(m_hListControl, 0, 1, buf);
- + if (it->second->Author().size())
- + _tcscpy_s(buf, 1024, it->second->Author().c_str());
- + else
- + _tcscpy_s(buf, 1024, _T("(no author)"));
- + ListView_SetItemText(m_hListControl, 0, 2, buf);
- + wstring msg = it->second->Message();
- + std::remove(msg.begin(), msg.end(), '\r');
- + std::replace(msg.begin(), msg.end(), '\n', ' ');
- + std::replace(msg.begin(), msg.end(), '\t', ' ');
- + _tcsncpy_s(buf, 1024, msg.c_str(), 1023);
- + ListView_SetItemText(m_hListControl, 0, 3, buf);
- - if ((iLastUnread < 0)&&(!it->second.read))
- - {
- - iLastUnread = 0;
- + if ((iLastUnread < 0)&&(!it->second->read))
- + {
- + iLastUnread = 0;
- + }
- + if (iLastUnread >= 0)
- + iLastUnread++;
- }
- - if (iLastUnread >= 0)
- - iLastUnread++;
- + gReviewBoard.ReleaseReadOnlyData();
- }
- ListView_SetSelectionMark(m_hListControl, selMark);
- m_bBlockListCtrlUI = false;
- @@ -2110,6 +2485,7 @@
- bChanged = true;
- it->second.read = true;
- }
- + gReviewBoard.ReviewsSetRead(info->url);
- // refresh the name of the tree item to indicate the new
- // number of unread log messages
- WCHAR * str = new WCHAR[info->name.size()+10];
- @@ -2208,124 +2584,246 @@
- return;
- if ((lpNMListView->uOldState ^ lpNMListView->uNewState) & LVIS_SELECTED)
- {
- - const map<wstring,CUrlInfo> * pRead = m_pURLInfos->GetReadOnlyData();
- LVITEM item = {0};
- item.mask = LVIF_PARAM;
- item.iItem = lpNMListView->iItem;
- ListView_GetItem(m_hListControl, &item);
- - SCCSLogEntry * pLogEntry = (SCCSLogEntry*)item.lParam;
- - if (pLogEntry)
- + if(m_commitsradio)
- {
- - HTREEITEM hSelectedItem = TreeView_GetSelection(m_hTreeControl);
- - // get the url this entry refers to
- - TVITEMEX itemex = {0};
- - itemex.hItem = hSelectedItem;
- - itemex.mask = TVIF_PARAM;
- - TreeView_GetItem(m_hTreeControl, &itemex);
- - if (itemex.lParam == 0)
- + const map<wstring,CUrlInfo> * pRead = m_pURLInfos->GetReadOnlyData();
- + SCCSLogEntry * pLogEntry = (SCCSLogEntry*)item.lParam;
- + if (pLogEntry)
- {
- - m_pURLInfos->ReleaseReadOnlyData();
- - return;
- - }
- - // set the entry as read
- - if ((!pLogEntry->read)&&(lpNMListView->uNewState & LVIS_SELECTED))
- - {
- - pLogEntry->read = true;
- - // refresh the name of the tree item to indicate the new
- - // number of unread log messages
- - // e.g. instead of 'TortoiseSVN (3)', show now 'TortoiseSVN (2)'
- - if (pRead->find(*(wstring*)itemex.lParam) != pRead->end())
- + HTREEITEM hSelectedItem = TreeView_GetSelection(m_hTreeControl);
- + // get the url this entry refers to
- + TVITEMEX itemex = {0};
- + itemex.hItem = hSelectedItem;
- + itemex.mask = TVIF_PARAM;
- + TreeView_GetItem(m_hTreeControl, &itemex);
- + if (itemex.lParam == 0)
- {
- - const CUrlInfo * uinfo = &pRead->find(*(wstring*)itemex.lParam)->second;
- - // count the number of unread messages
- - int unread = 0;
- - for (map<svn_revnum_t,SCCSLogEntry>::const_iterator it = uinfo->logentries.begin(); it != uinfo->logentries.end(); ++it)
- + m_pURLInfos->ReleaseReadOnlyData();
- + return;
- + }
- + // set the entry as read
- + if ((!pLogEntry->read)&&(lpNMListView->uNewState & LVIS_SELECTED))
- + {
- + pLogEntry->read = true;
- + // refresh the name of the tree item to indicate the new
- + // number of unread log messages
- + // e.g. instead of 'TortoiseSVN (3)', show now 'TortoiseSVN (2)'
- + if (pRead->find(*(wstring*)itemex.lParam) != pRead->end())
- {
- - if (!it->second.read)
- - unread++;
- + const CUrlInfo * uinfo = &pRead->find(*(wstring*)itemex.lParam)->second;
- + // count the number of unread messages
- + int unread = 0;
- + for (map<svn_revnum_t,SCCSLogEntry>::const_iterator it = uinfo->logentries.begin(); it != uinfo->logentries.end(); ++it)
- + {
- + if (!it->second.read)
- + unread++;
- + }
- + WCHAR * str = new WCHAR[uinfo->name.size()+30];
- + int unreadreviews = gReviewBoard.GetUnreadReviewsForUrl(uinfo->url);
- + if (unread || unreadreviews)
- + {
- + _stprintf_s(str, uinfo->name.size()+30, _T("%s (%d + %d)"), uinfo->name.c_str(), unread, unreadreviews);
- + itemex.state = TVIS_BOLD;
- + itemex.stateMask = TVIS_BOLD;
- + itemex.iImage = 3;
- + itemex.iSelectedImage = 3;
- + }
- + else
- + {
- + _stprintf_s(str, uinfo->name.size()+30, _T("%s"), uinfo->name.c_str());
- + itemex.state = 0;
- + itemex.stateMask = TVIS_BOLD;
- + itemex.iImage = 2;
- + itemex.iSelectedImage = 2;
- + }
- +
- + itemex.pszText = str;
- + itemex.mask = TVIF_TEXT|TVIF_STATE|TVIF_IMAGE|TVIF_SELECTEDIMAGE;
- + TreeView_SetItem(m_hTreeControl, &itemex);
- }
- - WCHAR * str = new WCHAR[uinfo->name.size()+10];
- - if (unread)
- + // the icon in the system tray needs to be changed back
- + // to 'normal'
- + ::SendMessage(m_hParent, COMMITMONITOR_CHANGEDINFO, (WPARAM)false, (LPARAM)0);
- + }
- + TCHAR buf[1024];
- + wstring msg;
- + if (ListView_GetSelectedCount(m_hListControl) > 1)
- + {
- + msg = _T("multiple log entries selected. Info for the last selected one:\n-------------------------------\n\n");
- + }
- + msg += pLogEntry->message.c_str();
- + msg += _T("\n\n-------------------------------\n");
- + // now add all changed paths, one path per line
- + for (map<std::wstring, SCCSLogChangedPaths>::const_iterator it = pLogEntry->m_changedPaths.begin(); it != pLogEntry->m_changedPaths.end(); ++it)
- + {
- + // action
- + msg += it->second.action;
- + bool mods = false;
- + if ((it->second.text_modified == svn_tristate_true)||(it->second.props_modified == svn_tristate_true))
- {
- - _stprintf_s(str, uinfo->name.size()+10, _T("%s (%d)"), uinfo->name.c_str(), unread);
- - itemex.state = TVIS_BOLD;
- - itemex.stateMask = TVIS_BOLD;
- - itemex.iImage = 3;
- - itemex.iSelectedImage = 3;
- + mods = true;
- }
- - else
- + if (mods)
- + msg += L"(";
- + if (it->second.text_modified == svn_tristate_true)
- + msg += L"T";
- + else if (mods)
- + msg += L" ";
- + if (it->second.props_modified == svn_tristate_true)
- + msg += L"P";
- + else if (mods)
- + msg += L" ";
- + if (mods)
- + msg += L")";
- + msg += _T(" : ");
- + msg += it->first;
- + msg += _T(" ");
- + if (!it->second.copyfrom_path.empty())
- {
- - _stprintf_s(str, uinfo->name.size()+10, _T("%s"), uinfo->name.c_str());
- - itemex.state = 0;
- - itemex.stateMask = TVIS_BOLD;
- - itemex.iImage = 2;
- - itemex.iSelectedImage = 2;
- + msg += _T("(copied from: ");
- + msg += it->second.copyfrom_path;
- + msg += _T(", revision ");
- + _stprintf_s(buf, 1024, _T("%ld)\n"), it->second.copyfrom_revision);
- + msg += wstring(buf);
- }
- + else
- + msg += _T("\n");
- + }
- - itemex.pszText = str;
- - itemex.mask = TVIF_TEXT|TVIF_STATE|TVIF_IMAGE|TVIF_SELECTEDIMAGE;
- - TreeView_SetItem(m_hTreeControl, &itemex);
- - }
- - // the icon in the system tray needs to be changed back
- - // to 'normal'
- - ::SendMessage(m_hParent, COMMITMONITOR_CHANGEDINFO, (WPARAM)false, (LPARAM)0);
- + CAppUtils::SearchReplace(msg, _T("\n"), _T("\r\n"));
- + SetWindowText(m_hLogMsgControl, msg.c_str());
- +
- + // find the diff name
- + _stprintf_s(buf, 1024, _T("%s_%ld.diff"), pRead->find(*(wstring*)itemex.lParam)->second.name.c_str(), pLogEntry->revision);
- + wstring diffFileName = CAppUtils::GetDataDir();
- + diffFileName += _T("\\");
- + diffFileName += wstring(buf);
- + SendMessage(m_hwndToolbar, TB_ENABLEBUTTON, ID_MAIN_SHOWDIFFCHOOSE, MAKELONG(true, 0));
- }
- - TCHAR buf[1024];
- - wstring msg;
- - if (ListView_GetSelectedCount(m_hListControl) > 1)
- + m_pURLInfos->ReleaseReadOnlyData();
- + }
- + else
- + {
- + ReviewBoardReview * pLogEntry = (ReviewBoardReview*)item.lParam; // conversion loses qualifiers, cast to non-const
- + const map<wstring,CUrlInfo> * pRead = m_pURLInfos->GetReadOnlyData();
- + if (pLogEntry)
- {
- - msg = _T("multiple log entries selected. Info for the last selected one:\n-------------------------------\n\n");
- - }
- - msg += pLogEntry->message.c_str();
- - msg += _T("\n\n-------------------------------\n");
- - // now add all changed paths, one path per line
- - for (map<std::wstring, SCCSLogChangedPaths>::const_iterator it = pLogEntry->m_changedPaths.begin(); it != pLogEntry->m_changedPaths.end(); ++it)
- - {
- - // action
- - msg += it->second.action;
- - bool mods = false;
- - if ((it->second.text_modified == svn_tristate_true)||(it->second.props_modified == svn_tristate_true))
- + HTREEITEM hSelectedItem = TreeView_GetSelection(m_hTreeControl);
- + // get the url this entry refers to
- + TVITEMEX itemex = {0};
- + itemex.hItem = hSelectedItem;
- + itemex.mask = TVIF_PARAM;
- + TreeView_GetItem(m_hTreeControl, &itemex);
- + if (itemex.lParam == 0)
- {
- - mods = true;
- + m_pURLInfos->ReleaseReadOnlyData();
- + return;
- }
- - if (mods)
- - msg += L"(";
- - if (it->second.text_modified == svn_tristate_true)
- - msg += L"T";
- - else if (mods)
- - msg += L" ";
- - if (it->second.props_modified == svn_tristate_true)
- - msg += L"P";
- - else if (mods)
- - msg += L" ";
- - if (mods)
- - msg += L")";
- - msg += _T(" : ");
- - msg += it->first;
- - msg += _T(" ");
- - if (!it->second.copyfrom_path.empty())
- + // set the entry as read
- + if ((!pLogEntry->read)&&(lpNMListView->uNewState & LVIS_SELECTED))
- {
- - msg += _T("(copied from: ");
- - msg += it->second.copyfrom_path;
- - msg += _T(", revision ");
- - _stprintf_s(buf, 1024, _T("%ld)\n"), it->second.copyfrom_revision);
- - msg += wstring(buf);
- + gReviewBoard.ReviewSetRead(pLogEntry->reviewid);
- + // refresh the name of the tree item to indicate the new
- + // number of unread log messages
- + // e.g. instead of 'TortoiseSVN (3)', show now 'TortoiseSVN (2)'
- + if (pRead->find(*(wstring*)itemex.lParam) != pRead->end())
- + {
- + const CUrlInfo * uinfo = &pRead->find(*(wstring*)itemex.lParam)->second;
- + // count the number of unread messages
- + int unread = 0;
- + for (map<svn_revnum_t,SCCSLogEntry>::const_iterator it = uinfo->logentries.begin(); it != uinfo->logentries.end(); ++it)
- + {
- + if (!it->second.read)
- + unread++;
- + }
- + WCHAR * str = new WCHAR[uinfo->name.size()+30];
- + int unreadreviews = gReviewBoard.GetUnreadReviewsForUrl(uinfo->url);
- + if (unread || unreadreviews)
- + {
- + _stprintf_s(str, uinfo->name.size()+30, _T("%s (%d + %d)"), uinfo->name.c_str(), unread, unreadreviews);
- + itemex.state = TVIS_BOLD;
- + itemex.stateMask = TVIS_BOLD;
- + itemex.iImage = 3;
- + itemex.iSelectedImage = 3;
- + }
- + else
- + {
- + _stprintf_s(str, uinfo->name.size()+30, _T("%s"), uinfo->name.c_str());
- + itemex.state = 0;
- + itemex.stateMask = TVIS_BOLD;
- + itemex.iImage = 2;
- + itemex.iSelectedImage = 2;
- + }
- +
- + itemex.pszText = str;
- + itemex.mask = TVIF_TEXT|TVIF_STATE|TVIF_IMAGE|TVIF_SELECTEDIMAGE;
- + TreeView_SetItem(m_hTreeControl, &itemex);
- + }
- + // the icon in the system tray needs to be changed back
- + // to 'normal'
- + ::SendMessage(m_hParent, COMMITMONITOR_CHANGEDINFO, (WPARAM)false, (LPARAM)0);
- }
- - else
- - msg += _T("\n");
- + TCHAR buf[1024];
- + wstring msg;
- + if (ListView_GetSelectedCount(m_hListControl) > 1)
- + {
- + msg = _T("multiple log entries selected. Info for the last selected one:\n-------------------------------\n\n");
- + }
- + msg += pLogEntry->Message().c_str();
- + msg += _T("\n\n-------------------------------\n");
- +/* // now add all changed paths, one path per line
- + for (map<std::wstring, SCCSLogChangedPaths>::const_iterator it = pLogEntry->m_changedPaths.begin(); it != pLogEntry->m_changedPaths.end(); ++it)
- + {
- + // action
- + msg += it->second.action;
- + bool mods = false;
- + if ((it->second.text_modified == svn_tristate_true)||(it->second.props_modified == svn_tristate_true))
- + {
- + mods = true;
- + }
- + if (mods)
- + msg += L"(";
- + if (it->second.text_modified == svn_tristate_true)
- + msg += L"T";
- + else if (mods)
- + msg += L" ";
- + if (it->second.props_modified == svn_tristate_true)
- + msg += L"P";
- + else if (mods)
- + msg += L" ";
- + if (mods)
- + msg += L")";
- + msg += _T(" : ");
- + msg += it->first;
- + msg += _T(" ");
- + if (!it->second.copyfrom_path.empty())
- + {
- + msg += _T("(copied from: ");
- + msg += it->second.copyfrom_path;
- + msg += _T(", revision ");
- + _stprintf_s(buf, 1024, _T("%ld)\n"), it->second.copyfrom_revision);
- + msg += wstring(buf);
- + }
- + else
- + msg += _T("\n");
- + }
- + */
- + CAppUtils::SearchReplace(msg, _T("\n"), _T("\r\n"));
- + SetWindowText(m_hLogMsgControl, msg.c_str());
- +
- + // find the diff name
- + _stprintf_s(buf, 1024, _T("%s_review_%s.diff"), pRead->find(*(wstring*)itemex.lParam)->second.name.c_str(), pLogEntry->Reviewid().c_str());
- + wstring diffFileName = CAppUtils::GetDataDir();
- + diffFileName += _T("\\");
- + diffFileName += wstring(buf);
- + SendMessage(m_hwndToolbar, TB_ENABLEBUTTON, ID_MAIN_SHOWDIFFCHOOSE, MAKELONG(true, 0));
- }
- -
- - CAppUtils::SearchReplace(msg, _T("\n"), _T("\r\n"));
- - SetWindowText(m_hLogMsgControl, msg.c_str());
- -
- - // find the diff name
- - _stprintf_s(buf, 1024, _T("%s_%ld.diff"), pRead->find(*(wstring*)itemex.lParam)->second.name.c_str(), pLogEntry->revision);
- - wstring diffFileName = CAppUtils::GetDataDir();
- - diffFileName += _T("\\");
- - diffFileName += wstring(buf);
- - SendMessage(m_hwndToolbar, TB_ENABLEBUTTON, ID_MAIN_SHOWDIFFCHOOSE, MAKELONG(true, 0));
- + m_pURLInfos->ReleaseReadOnlyData();
- }
- - m_pURLInfos->ReleaseReadOnlyData();
- }
- }
- @@ -2371,14 +2869,29 @@
- break;
- case CDDS_ITEMPREPAINT:
- {
- - SCCSLogEntry * pLogEntry = (SCCSLogEntry*)lpNMCustomDraw->nmcd.lItemlParam;
- + if(m_commitsradio)
- + {
- + SCCSLogEntry * pLogEntry = (SCCSLogEntry*)lpNMCustomDraw->nmcd.lItemlParam;
- - if (!pLogEntry->read)
- + if (!pLogEntry->read)
- + {
- + SelectObject(lpNMCustomDraw->nmcd.hdc, m_boldFont);
- + // We changed the font, so we're returning CDRF_NEWFONT. This
- + // tells the control to recalculate the extent of the text.
- + result = CDRF_NEWFONT;
- + }
- + }
- + else
- {
- - SelectObject(lpNMCustomDraw->nmcd.hdc, m_boldFont);
- - // We changed the font, so we're returning CDRF_NEWFONT. This
- - // tells the control to recalculate the extent of the text.
- - result = CDRF_NEWFONT;
- + ReviewBoardReview * pLogEntry = (ReviewBoardReview*)lpNMCustomDraw->nmcd.lItemlParam;
- +
- + if (!pLogEntry->read)
- + {
- + SelectObject(lpNMCustomDraw->nmcd.hdc, m_boldFont);
- + // We changed the font, so we're returning CDRF_NEWFONT. This
- + // tells the control to recalculate the extent of the text.
- + result = CDRF_NEWFONT;
- + }
- }
- }
- break;
- @@ -2504,18 +3017,40 @@
- ListView_GetItem(m_hListControl, &item);
- if (item.state & LVIS_SELECTED)
- {
- - SCCSLogEntry * pLogEntry = (SCCSLogEntry*)item.lParam;
- - // find the diff name
- - _stprintf_s(buf, 4096, _T("%s_%ld.diff"), pWrite->find(*(wstring*)itemex.lParam)->second.name.c_str(), pLogEntry->revision);
- - wstring diffFileName = CAppUtils::GetDataDir();
- - diffFileName += _T("\\");
- - diffFileName += wstring(buf);
- - DeleteFile(diffFileName.c_str());
- + if(m_commitsradio)
- + {
- + SCCSLogEntry * pLogEntry = (SCCSLogEntry*)item.lParam;
- + // find the diff name
- + _stprintf_s(buf, 4096, _T("%s_%ld.diff"), pWrite->find(*(wstring*)itemex.lParam)->second.name.c_str(), pLogEntry->revision);
- + wstring diffFileName = CAppUtils::GetDataDir();
- + diffFileName += _T("\\");
- + diffFileName += wstring(buf);
- + DeleteFile(diffFileName.c_str());
- - pWrite->find((*(wstring*)itemex.lParam))->second.logentries.erase(pLogEntry->revision);
- - ListView_DeleteItem(m_hListControl, i);
- - if (nFirstDeleted < 0)
- - nFirstDeleted = i;
- + pWrite->find((*(wstring*)itemex.lParam))->second.logentries.erase(pLogEntry->revision);
- + ListView_DeleteItem(m_hListControl, i);
- + if (nFirstDeleted < 0)
- + nFirstDeleted = i;
- + }
- + else
- + {
- + ReviewBoardReview * pLogEntry = (ReviewBoardReview*)item.lParam;
- + if(pLogEntry)
- + {
- + // find the diff name
- + _stprintf_s(buf, 1024, _T("%s_review_%s.diff"), pWrite->find(*(wstring*)itemex.lParam)->second.name.c_str(), pLogEntry->Reviewid().c_str());
- + wstring diffFileName = CAppUtils::GetDataDir();
- + diffFileName += _T("\\");
- + diffFileName += wstring(buf);
- + DeleteFile(diffFileName.c_str());
- +
- + gReviewBoard.DeleteReview(pLogEntry->reviewid);
- + pLogEntry = 0;
- + ListView_DeleteItem(m_hListControl, i);
- + if (nFirstDeleted < 0)
- + nFirstDeleted = i;
- + }
- + }
- }
- else
- ++i;
- @@ -2561,7 +3096,9 @@
- HDWP hdwp = BeginDeferWindowPos(9);
- hdwp = DeferWindowPos(hdwp, m_hwndToolbar, *this, 0, 0, width, m_topmarg, SWP_NOZORDER|SWP_NOACTIVATE);
- hdwp = DeferWindowPos(hdwp, hFilterLabel, *this, m_xSliderPos+4, m_topmarg+5, FILTERLABELWIDTH, 12, SWP_NOZORDER|SWP_NOACTIVATE|SWP_FRAMECHANGED);
- - hdwp = DeferWindowPos(hdwp, m_hFilterControl, *this, m_xSliderPos+4+FILTERLABELWIDTH, m_topmarg+1, width-m_xSliderPos-4-FILTERLABELWIDTH-4, FILTERBOXHEIGHT-1, SWP_NOZORDER|SWP_NOACTIVATE);
- + hdwp = DeferWindowPos(hdwp, m_hFilterControl, *this, m_xSliderPos+4+FILTERLABELWIDTH, m_topmarg+1, width-m_xSliderPos-4-FILTERLABELWIDTH-4 - m_radiossize, FILTERBOXHEIGHT-1, SWP_NOZORDER|SWP_NOACTIVATE);
- + hdwp = DeferWindowPos(hdwp, m_hCommitsRadio, *this, width - m_radiossize + 4, m_topmarg+1, 80, FILTERBOXHEIGHT-1, SWP_NOZORDER|SWP_NOACTIVATE);
- + hdwp = DeferWindowPos(hdwp, m_hReviewsRadio, *this, width - m_radiossize + 84, m_topmarg+1, 80, FILTERBOXHEIGHT-1, SWP_NOZORDER|SWP_NOACTIVATE);
- hdwp = DeferWindowPos(hdwp, m_hTreeControl, *this, 0, m_topmarg, m_xSliderPos, height-m_topmarg-m_bottommarg+FILTERBOXHEIGHT+4, SWP_NOZORDER|SWP_NOACTIVATE);
- hdwp = DeferWindowPos(hdwp, m_hListControl, *this, m_xSliderPos+4, m_topmarg+FILTERBOXHEIGHT, width-m_xSliderPos-4, m_ySliderPos-m_topmarg+4, SWP_NOZORDER|SWP_NOACTIVATE);
- hdwp = DeferWindowPos(hdwp, m_hLogMsgControl, *this, m_xSliderPos+4, m_ySliderPos+8+FILTERBOXHEIGHT, width-m_xSliderPos-4, height-m_bottommarg-m_ySliderPos-4, SWP_NOZORDER|SWP_NOACTIVATE);
- @@ -2872,9 +3409,13 @@
- loglist.left, treelist.top+5, 0, 0, SWP_NOACTIVATE|SWP_NOOWNERZORDER|SWP_NOZORDER|SWP_NOSIZE);
- hdwp = DeferWindowPos(hdwp, m_hFilterControl, NULL,
- - loglist.left+FILTERLABELWIDTH, treelist.top, loglist.right-FILTERLABELWIDTH, FILTERBOXHEIGHT,
- + loglist.left+FILTERLABELWIDTH, treelist.top, loglist.right-loglist.left-FILTERLABELWIDTH - 160 - 4, FILTERBOXHEIGHT,
- SWP_NOACTIVATE|SWP_NOOWNERZORDER|SWP_NOZORDER);
- + hdwp = DeferWindowPos(hdwp, m_hCommitsRadio, NULL, loglist.right - m_radiossize + 4, treelist.top + 1, 80, FILTERBOXHEIGHT-1, SWP_NOACTIVATE|SWP_NOOWNERZORDER|SWP_NOZORDER);
- + hdwp = DeferWindowPos(hdwp, m_hReviewsRadio, NULL, loglist.right - m_radiossize + 84, treelist.top + 1, 80, FILTERBOXHEIGHT-1, SWP_NOACTIVATE|SWP_NOOWNERZORDER|SWP_NOZORDER);
- +
- +
- hdwp = DeferWindowPos(hdwp, m_hListControl, NULL,
- loglist.left, treelist.top+FILTERBOXHEIGHT, loglist.right-loglist.left, loglist.bottom-treelist.top-FILTERBOXHEIGHT,
- SWP_NOACTIVATE|SWP_NOOWNERZORDER|SWP_NOZORDER);
- Index: src/MainDlg.h
- ===================================================================
- --- src/MainDlg.h (revision 605)
- +++ src/MainDlg.h (working copy)
- @@ -97,6 +97,8 @@
- HWND m_hListControl;
- HWND m_hLogMsgControl;
- HWND m_hFilterControl;
- + HWND m_hCommitsRadio;
- + HWND m_hReviewsRadio;
- HFONT m_font;
- CListCtrl m_ListCtrl;
- @@ -112,6 +114,8 @@
- LONG m_xSliderPos;
- LONG m_ySliderPos;
- LONG m_bottommarg;
- + LONG m_radiossize;
- + bool m_commitsradio;
- HFONT m_boldFont;
- Index: src/Resources/CommitMonitor.rc
- ===================================================================
- --- src/Resources/CommitMonitor.rc (revision 605)
- +++ src/Resources/CommitMonitor.rc (working copy)
- @@ -21,7 +21,7 @@
- #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU)
- LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
- -#pragma code_page(1252)
- +#pragma code_page(1250)
- /////////////////////////////////////////////////////////////////////////////
- //
- @@ -103,8 +103,10 @@
- LTEXT "",IDC_INFOLABEL,0,222,303,16
- PUSHBUTTON "&Exit",IDC_EXIT,359,222,50,14
- DEFPUSHBUTTON "&Hide",IDOK,304,222,50,14
- - EDITTEXT IDC_FILTERSTRING,186,32,225,14,ES_AUTOHSCROLL
- + EDITTEXT IDC_FILTERSTRING,186,32,141,14,ES_AUTOHSCROLL
- LTEXT "Filter:",IDC_FILTERLABEL,158,34,26,8
- + CONTROL "Commits",IDC_RADIO2,"Button",BS_AUTORADIOBUTTON,331,35,40,10
- + CONTROL "Reviews",IDC_RADIO3,"Button",BS_AUTORADIOBUTTON,371,35,40,10
- END
- IDD_URLCONFIG DIALOGEX 0, 0, 336, 322
- @@ -144,6 +146,7 @@
- COMBOBOX IDC_SCCSCOMBO,89,23,110,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
- LTEXT "Accurev Repository:",IDC_REPOLABEL,14,70,66,8
- EDITTEXT IDC_ACCUREVREPO,89,67,233,14,ES_AUTOHSCROLL
- + CONTROL "Check review requests",IDC_CHECKREVIEWS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,223,91,89,10
- END
- IDD_OPTIONS DIALOGEX 0, 0, 308, 293
- @@ -270,6 +273,10 @@
- BOTTOMMARGIN, 286
- END
- + IDD_FINDBAR, DIALOG
- + BEGIN
- + END
- +
- IDD_NEWERNOTIFYDLG, DIALOG
- BEGIN
- LEFTMARGIN, 7
- @@ -365,7 +372,7 @@
- POPUP "Popup"
- BEGIN
- MENUITEM "&Show Unified Diff", ID_MAIN_SHOWDIFF
- - MENUITEM "&Open WebViewer", ID_POPUP_OPENWEBVIEWER, INACTIVE
- + MENUITEM "&Open WebViewer", ID_POPUP_OPENWEBVIEWER
- MENUITEM "&Remove", ID_MAIN_REMOVE
- MENUITEM "&Mark as unread", ID_POPUP_MARKASUNREAD
- MENUITEM "&Copy to clipboard", ID_MAIN_COPY
- Index: src/Resources/resource.h
- ===================================================================
- --- src/Resources/resource.h (revision 605)
- +++ src/Resources/resource.h (working copy)
- @@ -104,6 +104,7 @@
- #define IDC_NUMLOGS 1040
- #define IDC_CHECK2 1041
- #define IDC_NOTIFYCONNECTERROR 1041
- +#define IDC_CHECKREVIEWS 1041
- #define IDC_FILTERSTRING 1042
- #define IDC_FILTERLABEL 1043
- #define IDC_MAXLOGENTRIES 1044
- @@ -130,6 +131,8 @@
- #define IDC_ACCUDIFFCMDLABEL 1064
- #define IDC_SCCSCOMBO 1065
- #define IDC_EDIT2 1069
- +#define IDC_RADIO2 1072
- +#define IDC_RADIO3 1074
- #define ID_FILE_OPENCOMMITMONITOR 32771
- #define ID_MAIN_OPENCOMMITMONITOR 32772
- #define ID_POPUP_OPENCOMMITMONITOR 32773
- @@ -181,7 +184,7 @@
- #define _APS_NO_MFC 1
- #define _APS_NEXT_RESOURCE_VALUE 165
- #define _APS_NEXT_COMMAND_VALUE 32836
- -#define _APS_NEXT_CONTROL_VALUE 1070
- +#define _APS_NEXT_CONTROL_VALUE 1073
- #define _APS_NEXT_SYMED_VALUE 110
- #endif
- #endif
- Index: src/ReviewBoardXml.cpp
- ===================================================================
- --- src/ReviewBoardXml.cpp (revision 0)
- +++ src/ReviewBoardXml.cpp (revision 0)
- @@ -0,0 +1,737 @@
- +#include "stdafx.h"
- +
- +#include "ReviewBoardXml.h"
- +#include "rapidxml.hpp"
- +#include <fstream>
- +#include <time.h>
- +#include "timesupport.h"
- +#include "Http.h"
- +
- +#include "UnicodeUtils.h"
- +#include "AppUtils.h"
- +
- +using namespace rapidxml;
- +using namespace std;
- +
- +#define GET_REVIEWS_BASE "/api/review-requests/"
- +#define GET_REVIEWS "/api/review-requests/?status=all&max-results=30"
- +#define GET_REVIEWS_FROM "&time-added-from="
- +#define GET_REVIEW_ID "/api/review-requests/"
- +#define GET_UNIDIFF_1 "/api/review-requests/"
- +#define GET_UNIDIFF_2 "/diffs/1/"
- +#define GET_FILES_1 "/api/review-requests/"
- +#define GET_FILES_2 "/diffs/1/files/"
- +
- +
- +
- +time_t ReviewBoard::Now()
- +{
- + return time(NULL);
- +}
- +
- +time_t ReviewBoard::FromISO8601(const std::string& timestr)
- +{
- + if(timestr == "0000-00-00T00:00:00")
- + return (time_t)0;
- + struct tm tm;
- + if(NULL == strptime(timestr.c_str(),"%Y-%m-%dT%H:%M:%S",&tm))
- + return (time_t)0;
- + return mktime(&tm);
- +}
- +
- +std::string ReviewBoard::ToISO8601(time_t tim)
- +{
- + if(tim == 0)
- + return string("0000-00-00T00:00:00");
- + char buf[128];
- + memset(buf,0,128);
- + strftime(buf,128,"%Y-%m-%dT%H:%M:%S",localtime(&tim));
- + return string(buf);
- +}
- +
- +ReviewBoardXmlNode::~ReviewBoardXmlNode()
- +{
- + while(!children.empty())
- + {
- + delete children.back();
- + children.pop_back();
- + }
- +}
- +
- +void ReviewBoardXmlNode::Load(void* rapidnode, ReviewBoardXmlNode * paren)
- +{
- + parent = paren;
- +
- + xml_node<> *rnode = (xml_node<>*)rapidnode;
- +
- + name.insert(0,rnode->name(),rnode->name_size());
- +/*
- + the xml output from the reviewboard doesn't contain attributes
- + for (xml_attribute<> *attr = rnode->first_attribute();
- + attr; attr = attr->next_attribute())
- + {
- + }
- +*/
- + for(rnode = rnode->first_node();rnode;rnode = rnode->next_sibling())
- + {
- + if(rnode->value_size() != 0)
- + {
- + string name, val;
- + name.insert(0,rnode->name(),rnode->name_size());
- + val.insert(0,rnode->value(),rnode->value_size());
- + attributes[name] = val;
- + }
- + else
- + {
- + ReviewBoardXmlNode * child = new ReviewBoardXmlNode();
- + child->Load(rnode,this);
- + children.push_back(child);
- + }
- + }
- +}
- +
- +ReviewBoardXmlNode const * ReviewBoardXmlNode::GetNodeWithAttributeAndValue(const std::string& attr, const std::string& val) const
- +{
- + map<string,string>::const_iterator itr = attributes.find(attr);
- + if(itr != attributes.end() && itr->second == val)
- + return this;
- +
- + for(vector<ReviewBoardXmlNode*>::const_iterator it = children.begin(); it != children.end(); ++it)
- + {
- + ReviewBoardXmlNode const * ret = (*it)->GetNodeWithAttributeAndValue(attr,val);
- + if(ret)
- + return ret;
- + }
- +
- + return 0;
- +}
- +
- +ReviewBoardXmlNode const * ReviewBoardXmlNode::GetFirstNodeWithAttribute(const std::string& nam, const std::string& attr) const
- +{
- + map<string,string>::const_iterator itr = attributes.find(attr);
- + if(name == nam && itr != attributes.end())
- + return this;
- +
- + for(vector<ReviewBoardXmlNode*>::const_iterator it = children.begin(); it != children.end(); ++it)
- + {
- + ReviewBoardXmlNode const * ret = (*it)->GetFirstNodeWithAttribute(nam, attr);
- + if(ret)
- + return ret;
- + }
- +
- + return 0;
- +}
- +
- +void ReviewBoardXmlNode::GetNodesVectorWithAttribute(const std::string& attr, std::vector<ReviewBoardXmlNode const*>& nodes) const
- +{
- + if(attributes.find(attr) != attributes.end())
- + nodes.push_back(this);
- + for(vector<ReviewBoardXmlNode*>::const_iterator it = children.begin(); it != children.end(); ++it)
- + (*it)->GetNodesVectorWithAttribute(attr,nodes);
- +}
- +
- +
- +void ReviewBoardXmlDocument::Cleanup()
- +{
- + if(root)
- + delete root;
- + root = 0;
- +}
- +
- +
- +ReviewBoardXmlDocument::~ReviewBoardXmlDocument()
- +{
- + Cleanup();
- +}
- +
- +void ReviewBoardXmlDocument::LoadBuf(const string& buffer)
- +{
- + char * buf;
- + int len;
- +
- + len = buffer.length();
- + buf = new char[len+1];
- + memcpy(buf,buffer.c_str(),len);
- + buf[len] = 0;
- +
- + xml_document<> doc; // character type defaults to char
- + doc.parse<0>(buf); // 0 means default parse flags
- +
- + xml_node<> * rapidnode = doc.first_node();
- +
- + root = new ReviewBoardXmlNode();
- +
- + if(rapidnode)
- + root->Load(rapidnode,NULL);
- +
- + delete[] buf;
- +
- + value.write(buffer.c_str(),buffer.length());
- +}
- +
- +void ReviewBoardXmlDocument::Load(const string& path)
- +{
- + Cleanup();
- +
- + stringstream sstrm;
- + gHTTP.GetPageXml(path,sstrm);
- +
- + LoadBuf(sstrm.str());
- +}
- +
- +void ReviewBoardTextDocument::Load(const string& path)
- +{
- + gHTTP.GetPageText(path,value);
- +}
- +
- +void ReviewBoardReviewUnifiedDiff::Open(const char * review)
- +{
- + string path = GET_UNIDIFF_1;
- + path += review;
- + path += GET_UNIDIFF_2;
- + Load(path);
- +}
- +
- +void ReviewBoardAllReviews::Open(const char * from_time)
- +{
- + string path = GET_REVIEWS;
- + if(from_time)
- + {
- + path += GET_REVIEWS_FROM;
- + path += from_time;
- + }
- + Load(path);
- +}
- +
- +void ReviewBoardReview::Open(const char * id)
- +{
- + string path = GET_REVIEW_ID;
- + path += id;
- + path += "/";
- + Load(path);
- +}
- +
- +void ReviewBoardReviewFiles::Open(const char * id)
- +{
- + string path = GET_FILES_1;
- + path += id;
- + path += GET_FILES_2;
- + Load(path);
- +}
- +
- +ReviewBoardXmlNode const * ReviewBoardXmlDocument::GetNodeWithAttributeAndValue(const std::string& attr, const std::string& val) const
- +{
- + if(root)
- + return root->GetNodeWithAttributeAndValue(attr,val);
- + return 0;
- +}
- +
- +void ReviewBoardXmlDocument::GetNodesVectorWithAttribute(const std::string& attr, std::vector<ReviewBoardXmlNode const*>& nodes) const
- +{
- + if(root)
- + return root->GetNodesVectorWithAttribute(attr,nodes);
- +}
- +
- +ReviewBoardXmlNode const * ReviewBoardXmlDocument::GetFirstNodeWithAttribute(const std::string& name, const std::string& attr) const
- +{
- + if(root)
- + return root->GetFirstNodeWithAttribute(name, attr);
- + return 0;
- +}
- +
- +
- +typedef vector<ReviewBoardXmlNode const *> rbxvec;
- +
- +void ReviewBoard::GetAllNeededData_FirstPass(const char * from_time)
- +{
- + ReviewBoardAllReviews * rbd = new ReviewBoardAllReviews();
- + rbd->Open(from_time);
- + all_docs.push_back(rbd);
- +
- + rbxvec vec;
- + rbd->GetNodesVectorWithAttribute("id",vec);
- + for(rbxvec::const_iterator itr = vec.begin(); itr != vec.end(); ++itr)
- + {
- + string id = (*itr)->attributes.at("id");
- + // if not cached already
- + if(reviewid_to_files.find(id) == reviewid_to_files.end())
- + {
- + ReviewBoardReviewFiles * rbf = new ReviewBoardReviewFiles();
- +
- + rbf->Open(id.c_str());
- + reviewid_to_files[id] = rbf;
- +
- + all_docs.push_back(rbf);
- + }
- + }
- +}
- +
- +void ReviewBoard::GetSpecificReviewData_SecondPass(const std::vector<std::string>& branches)
- +{
- + for(R2Fmap::const_iterator itr = reviewid_to_files.begin(); itr != reviewid_to_files.end(); ++itr)
- + {
- + // if not cached already
- + if(reviewid_to_review.find(itr->first) == reviewid_to_review.end())
- + {
- + if(itr->second->HasMatch(branches))
- + {
- + ReviewBoardReview * rbr = new ReviewBoardReview();
- + rbr->Open(itr->first.c_str());
- + rbr->reviewid = itr->first;
- + reviewid_to_review[itr->first] = rbr;
- + all_docs.push_back(rbr);
- + }
- + }
- + }
- +}
- +
- +bool ReviewBoardReviewFiles::HasMatch(const std::string& branch)
- +{
- + rbxvec vec;
- + GetNodesVectorWithAttribute("source_file",vec);
- + for(rbxvec::const_iterator it = vec.begin(); it != vec.end(); ++it)
- + {
- + const std::string& str = (*it)->attributes.at("source_file");
- + if(str.find(branch) != string::npos)
- + return true;
- + }
- + return false;
- +}
- +
- +
- +bool ReviewBoardReviewFiles::HasMatch(const std::vector<std::string>& branches)
- +{
- + rbxvec vec;
- + GetNodesVectorWithAttribute("source_file",vec);
- + for(rbxvec::const_iterator it = vec.begin(); it != vec.end(); ++it)
- + {
- + const std::string& str = (*it)->attributes.at("source_file");
- + for(std::vector<std::string>::const_iterator itr = branches.begin(); itr != branches.end(); ++itr)
- + {
- + if(str.find(*itr) != string::npos)
- + return true;
- + }
- + }
- + return false;
- +}
- +
- +ReviewBoard::~ReviewBoard()
- +{
- + // do not destroy while other threads are accessing the object
- + guard.AcquireWriterLock();
- + while(!all_docs.empty())
- + {
- + delete all_docs.back();
- + all_docs.pop_back();
- + }
- +}
- +
- +vector<ReviewBoardXmlDocument*> const * ReviewBoard::GetReadOnlyData()
- +{
- + guard.AcquireReaderLock();
- + return &all_docs;
- +}
- +
- +void ReviewBoard::ReleaseReadOnlyData()
- +{
- + guard.ReleaseReaderLock();
- +}
- +
- +void ReviewBoard::Save(const std::wstring& filename)
- +{
- + guard.AcquireReaderLock();
- +
- + if(filename != TEXT(""))
- + savefilename = filename;
- +
- + if(savefilename == TEXT(""))
- + savefilename = CAppUtils::GetDataDir() + TEXT("\\reviews");
- +
- + ofstream ofile(savefilename.c_str());
- +
- +
- + ofile << ToISO8601(lastupdate) << endl;
- + ofile << url_to_branch.size() << endl;
- + for(U2Bmap::const_iterator itr = url_to_branch.begin(); itr != url_to_branch.end(); ++itr)
- + {
- + ofile << itr->first << endl;
- + ofile << itr->second << endl;
- + }
- +
- + ofile << reviewid_to_files.size() << endl;
- +
- + for(R2Fmap::const_iterator itr = reviewid_to_files.begin(); itr != reviewid_to_files.end(); ++itr)
- + {
- + ofile << itr->first << endl;
- + ofile << itr->second->value.str().length() << endl;
- + ofile.write(itr->second->value.str().c_str(),itr->second->value.str().length());
- + }
- +
- + ofile << reviewid_to_review.size() << endl;
- +
- + for(R2Rmap::const_iterator itr = reviewid_to_review.begin(); itr != reviewid_to_review.end(); ++itr)
- + {
- + ofile << itr->first << endl;
- + ofile << (itr->second->read ? "1" : "0") << endl;
- + ofile << itr->second->value.str().length() << endl;
- + ofile.write(itr->second->value.str().c_str(),itr->second->value.str().length());
- + }
- +
- +
- + ofile.close();
- +
- + guard.ReleaseReaderLock();
- +}
- +
- +void ReviewBoard::Load(const std::wstring& filename)
- +{
- + guard.AcquireWriterLock();
- +
- + if(filename != TEXT(""))
- + savefilename = filename;
- +
- + if(savefilename == TEXT(""))
- + savefilename = CAppUtils::GetDataDir() + TEXT("\\reviews");
- +
- + ifstream ifile(savefilename.c_str());
- +
- +
- + std::string timestr;
- + ifile >> timestr;
- + lastupdate = FromISO8601(timestr);
- + int numbranches;
- + ifile >> numbranches;
- + for(int i = 0; i < numbranches; ++i)
- + {
- + string url, branch;
- + ifile >> url;
- + ifile >> branch;
- + url_to_branch[url] = branch;
- + }
- +
- + int filesnum;
- + ifile >> filesnum;
- +
- + for(int i = 0; i < filesnum; ++i)
- + {
- + string review;
- + ifile >> review;
- + int len;
- + ifile >> len;
- + ifile.get();// eat eol
- + string buf(len,0);
- + int j = 0;
- + while(j < len)
- + {
- + buf[j] = ifile.get();
- + ++j;
- + }
- + ReviewBoardReviewFiles * r = new ReviewBoardReviewFiles();
- + r->LoadBuf(buf);
- + reviewid_to_files[review] = r;
- + all_docs.push_back(r);
- + }
- +
- + ifile >> filesnum;
- +
- + for(int i = 0; i < filesnum; ++i)
- + {
- + string review;
- + ifile >> review;
- + int read;
- + ifile >> read;
- + int len;
- + ifile >> len;
- + ifile.get();// eat eol
- + string buf(len,0);
- + int j = 0;
- + while(j < len)
- + {
- + buf[j] = ifile.get();
- + ++j;
- + }
- + ReviewBoardReview * r = new ReviewBoardReview();
- + r->read = (read == 1);
- + r->LoadBuf(buf);
- + r->reviewid = review;
- + reviewid_to_review[review] = r;
- + all_docs.push_back(r);
- + }
- +
- +
- + ifile.close();
- +
- + guard.ReleaseWriterLock();
- +}
- +
- +int ReviewBoard::DoUpdate()
- +{
- + guard.AcquireWriterLock();
- +
- + // set already dl-d reviews to old
- + for(R2Rmap::iterator itr = reviewid_to_review.begin();itr != reviewid_to_review.end(); ++itr)
- + itr->second->old = true;
- +
- + int filesnum = reviewid_to_files.size();
- + if(lastupdate != 0)
- + GetAllNeededData_FirstPass(ToISO8601(lastupdate).c_str());
- + else
- + GetAllNeededData_FirstPass();
- +
- + lastupdate = time(NULL);
- + filesnum -= reviewid_to_files.size();
- +
- + std::vector<std::string> vec;
- +
- + for(U2Bmap::const_iterator itr = url_to_branch.begin(); itr != url_to_branch.end(); ++itr)
- + {
- + vec.push_back(itr->second);
- + }
- +
- + int revsnum = reviewid_to_review.size();
- + GetSpecificReviewData_SecondPass(vec);
- + revsnum -= reviewid_to_review.size();
- +
- + guard.ReleaseWriterLock();
- + if(filesnum < 0)
- + Save();
- +
- + newreviews = -revsnum;
- +
- + return newreviews;
- +}
- +
- +void ReviewBoard::AddBranchToMonitor(const string& url, const string& branch)
- +{
- + guard.AcquireWriterLock();
- + url_to_branch[url] = branch;
- + guard.ReleaseWriterLock();
- +}
- +
- +void ReviewBoard::AddBranchToMonitor(const wstring& wurl)
- +{
- + std::string url = CUnicodeUtils::StdGetUTF8(wurl);
- + std::string branch = url;
- + size_t pos = branch.find("/code/");
- + if(pos != string::npos)
- + {
- + branch = branch.substr(pos+6);
- + }
- + AddBranchToMonitor(url,branch);
- +}
- +
- +
- +void ReviewBoard::RemoveBranchToMonitor(const wstring& wurl)
- +{
- + RemoveBranchToMonitor(CUnicodeUtils::StdGetUTF8(wurl));
- +}
- +
- +
- +void ReviewBoard::RemoveBranchToMonitor(const string& url)
- +{
- + guard.AcquireWriterLock();
- + U2Bmap::iterator itr = url_to_branch.find(url);
- + if(itr != url_to_branch.end())
- + url_to_branch.erase(url);
- + guard.ReleaseWriterLock();
- +}
- +
- +bool ReviewBoard::IsUrlMonitored(const std::string& url)
- +{
- + guard.AcquireReaderLock();
- + U2Bmap::const_iterator itr = url_to_branch.find(url);
- + if(itr != url_to_branch.end())
- + {
- + guard.ReleaseReaderLock();
- + return true;
- + }
- + guard.ReleaseReaderLock();
- + return false;
- +}
- +
- +bool ReviewBoard::IsUrlMonitored(const std::wstring& wurl)
- +{
- + std::string url = CUnicodeUtils::StdGetUTF8(wurl);
- + return IsUrlMonitored(url);
- +}
- +
- +typedef std::vector<ReviewBoardReview const *> rbrvec;
- +void ReviewBoard::GetReviewsForUrl(const std::wstring& wurl, WR2Rmap& vec)
- +{
- + std::string url = CUnicodeUtils::StdGetUTF8(wurl);
- + guard.AcquireReaderLock();
- + U2Bmap::const_iterator itr = url_to_branch.find(url);
- + if(itr != url_to_branch.end())
- + {
- + for(R2Fmap::const_iterator filesitr = reviewid_to_files.begin(); filesitr != reviewid_to_files.end(); ++filesitr)
- + {
- + if(filesitr->second->HasMatch(itr->second))
- + {
- + R2Rmap::const_iterator ritr = reviewid_to_review.find(filesitr->first);
- + if(ritr != reviewid_to_review.end())
- + vec[UTF8ToWide(ritr->first)] = (const_cast<ReviewBoardReview const *>(ritr->second));
- + }
- + }
- + }
- + guard.ReleaseReaderLock();
- +}
- +
- +int ReviewBoard::GetUnreadReviews()
- +{
- + guard.AcquireReaderLock();
- + int ret = 0;
- + for(R2Rmap::const_iterator ritr = reviewid_to_review.begin(); ritr != reviewid_to_review.end(); ++ritr)
- + {
- + if(!ritr->second->read)
- + ++ret;
- + }
- + guard.ReleaseReaderLock();
- + return ret;
- +}
- +
- +int ReviewBoard::GetNewReviewsForUrl(const std::wstring& url)
- +{
- + WR2Rmap v;
- + GetReviewsForUrl(url,v);
- + int n = 0;
- + for(WR2Rmap::const_iterator it = v.begin(); it != v.end(); ++it)
- + {
- + if(!it->second->old)
- + n++;
- + }
- + return n;
- +}
- +
- +int ReviewBoard::GetUnreadReviewsForUrl(const std::wstring& url)
- +{
- + WR2Rmap v;
- + GetReviewsForUrl(url,v);
- + int n = 0;
- + for(WR2Rmap::const_iterator it = v.begin(); it != v.end(); ++it)
- + {
- + if(!it->second->read)
- + n++;
- + }
- + return n;
- +}
- +
- +void ReviewBoard::ReviewSetRead(const std::string& rev, bool b)
- +{
- + guard.AcquireWriterLock();
- + R2Rmap::iterator ritr = reviewid_to_review.find(rev);
- + bool needsave = false;
- + if(ritr != reviewid_to_review.end())
- + {
- + if(ritr->second->read != b)
- + needsave = true;
- + ritr->second->read = b;
- + }
- + guard.ReleaseWriterLock();
- + if(needsave)
- + Save();
- +}
- +
- +void ReviewBoard::DeleteReview(const std::string& rev)
- +{
- + guard.AcquireWriterLock();
- + R2Rmap::iterator ritr = reviewid_to_review.find(rev);
- + bool needsave = false;
- + if(ritr != reviewid_to_review.end())
- + {
- + std::vector<ReviewBoardXmlDocument*>::iterator it2 = all_docs.begin();
- + while(it2 != all_docs.end())
- + {
- + if((*it2) == (ritr->second))
- + break;
- + it2++;
- + }
- +
- + if(!ritr->second->old)
- + newreviews--;
- +
- + delete (*it2);
- +
- + if(it2 != all_docs.end())
- + all_docs.erase(it2);
- +
- + reviewid_to_review.erase(ritr);
- + needsave = true;
- + }
- + guard.ReleaseWriterLock();
- + if(needsave)
- + Save();
- +}
- +
- +
- +void ReviewBoardTextDocument::Save(const wstring& filename)
- +{
- + ofstream ofile(filename.c_str());
- + ofile.write(value.str().c_str(),value.str().length());
- + ofile.close();
- +}
- +
- +void ReviewBoard::ReviewsSetRead(const std::wstring& wurl)
- +{
- + std::string url = CUnicodeUtils::StdGetUTF8(wurl);
- + guard.AcquireWriterLock();
- + U2Bmap::const_iterator itr = url_to_branch.find(url);
- + if(itr != url_to_branch.end())
- + {
- + for(R2Fmap::const_iterator filesitr = reviewid_to_files.begin(); filesitr != reviewid_to_files.end(); ++filesitr)
- + {
- + if(filesitr->second->HasMatch(itr->second))
- + {
- + R2Rmap::iterator ritr = reviewid_to_review.find(filesitr->first);
- + if(ritr != reviewid_to_review.end())
- + ritr->second->read = true;
- + }
- + }
- + }
- + guard.ReleaseWriterLock();
- + Save();
- +}
- +
- +wstring ReviewBoardReview::Author() const
- +{
- + ReviewBoardXmlNode const * n = GetFirstNodeWithAttribute("submitter","title");
- + if(n)
- + {
- + return UTF8ToWide(n->attributes.at("title"));
- + }
- + return TEXT("no author");
- +}
- +
- +wstring ReviewBoardReview::Date() const
- +{
- + ReviewBoardXmlNode const * n = GetFirstNodeWithAttribute("review_request","time_added");
- + if(n)
- + {
- + return UTF8ToWide(n->attributes.at("time_added"));
- + }
- + return TEXT("(no date)");
- +}
- +
- +wstring ReviewBoardReview::Url() const
- +{
- + ReviewBoardXmlNode const * n = GetFirstNodeWithAttribute("self","href");
- + if(n)
- + {
- + return UTF8ToWide(n->attributes.at("href"));
- + }
- + return TEXT("");
- +}
- +
- +wstring ReviewBoardReview::Message() const
- +{
- + ReviewBoardXmlNode const * n = GetFirstNodeWithAttribute("review_request","description");
- + if(n)
- + {
- + return UTF8ToWide(n->attributes.at("description"));
- + }
- + return TEXT("(no description)");
- +}
- +
- +wstring ReviewBoardReview::Reviewid() const
- +{
- + return UTF8ToWide(reviewid);
- +}
- Index: src/ReviewBoardXml.h
- ===================================================================
- --- src/ReviewBoardXml.h (revision 0)
- +++ src/ReviewBoardXml.h (revision 0)
- @@ -0,0 +1,167 @@
- +#ifndef REVIEWBOARDXML_H
- +#define REVIEWBOARDXML_H
- +
- +#include "stdafx.h"
- +
- +#include "ReaderWriterLock.h"
- +#include "Singleton.h"
- +
- +#include <string>
- +#include <sstream>
- +#include <vector>
- +#include <map>
- +
- +class ReviewBoardXmlNode
- +{
- +public:
- + std::string name;
- + ReviewBoardXmlNode * parent;
- + std::map<std::string,std::string> attributes;
- + std::vector<ReviewBoardXmlNode*> children;
- +public:
- + ReviewBoardXmlNode() : parent(0) {}
- + ~ReviewBoardXmlNode();
- + void Load(void* rapidnode, ReviewBoardXmlNode * parent);
- + ReviewBoardXmlNode const * GetNodeWithAttributeAndValue(const std::string& attr, const std::string& val) const;
- + void GetNodesVectorWithAttribute(const std::string& attr, std::vector<ReviewBoardXmlNode const*>& nodes) const;
- + ReviewBoardXmlNode const * GetFirstNodeWithAttribute(const std::string& name, const std::string& attr) const;
- +};
- +
- +enum ReviewBoardDocumentType
- +{
- + RBDT_BASE = 0,
- + RBDT_XML,
- + RBDT_TEXT,
- + RBDT_UNIDIFF,
- + RBDT_ALLREVIEWS,
- + RBDT_REVIEW,
- + RBDT_REVIEWFILES
- +};
- +
- +class ReviewBoardDocument
- +{
- +public:
- + std::stringstream value;
- +public:
- + virtual ReviewBoardDocumentType GetType() { return RBDT_BASE; }
- +};
- +
- +class ReviewBoardXmlDocument : public ReviewBoardDocument
- +{
- +public:
- + ReviewBoardXmlNode * root;
- +public:
- + ReviewBoardXmlDocument() : root(0) {}
- + ~ReviewBoardXmlDocument();
- + void Cleanup();
- + void LoadBuf(const std::string& buf);
- + void Load(const std::string& path);
- + ReviewBoardXmlNode const * GetNodeWithAttributeAndValue(const std::string& attr, const std::string& val) const;
- + void GetNodesVectorWithAttribute(const std::string& attr, std::vector<ReviewBoardXmlNode const*>& nodes) const;
- + ReviewBoardXmlNode const * GetFirstNodeWithAttribute(const std::string& name, const std::string& attr) const;
- + virtual ReviewBoardDocumentType GetType() { return RBDT_XML; }
- +};
- +
- +class ReviewBoardTextDocument : public ReviewBoardDocument
- +{
- +public:
- + void Load(const std::string& path);
- + virtual ReviewBoardDocumentType GetType() { return RBDT_TEXT; }
- + void Save(const std::wstring& filename);
- +};
- +
- +class ReviewBoardReviewUnifiedDiff : public ReviewBoardTextDocument
- +{
- +public:
- + std::string review;
- +public:
- + void Open(const char * reviewrequest);
- + virtual ReviewBoardDocumentType GetType() { return RBDT_UNIDIFF; }
- +};
- +
- +class ReviewBoardAllReviews : public ReviewBoardXmlDocument
- +{
- +public:
- + void Open(const char * from_time = 0);
- + virtual ReviewBoardDocumentType GetType() { return RBDT_ALLREVIEWS; }
- +};
- +
- +class ReviewBoardReview : public ReviewBoardXmlDocument
- +{
- +public:
- + std::string reviewid;
- + bool read;
- + bool old;
- + ReviewBoardReview() : read(false), old(false) {}
- +public:
- + void Open(const char * reviewid);
- + virtual ReviewBoardDocumentType GetType() { return RBDT_REVIEW; }
- + std::wstring Author() const;
- + std::wstring Message() const;
- + std::wstring Date() const;
- + std::wstring Reviewid() const;
- + std::wstring Url() const;
- +};
- +
- +class ReviewBoardReviewFiles : public ReviewBoardXmlDocument
- +{
- +public:
- + void Open(const char * reviewid);
- + virtual ReviewBoardDocumentType GetType() { return RBDT_REVIEWFILES; }
- + bool HasMatch(const std::vector<std::string>& branches);
- + bool HasMatch(const std::string& branch);
- +};
- +
- +class ReviewBoard
- +{
- +private:
- + friend class Singleton<ReviewBoard>;
- + ReviewBoard() : lastupdate(0), savefilename(TEXT("")), newreviews(0) {}
- + std::vector<ReviewBoardXmlDocument*> all_docs;
- + typedef std::map<std::string/*review id*/,ReviewBoardReviewFiles*> R2Fmap;
- + R2Fmap reviewid_to_files;
- + typedef std::map<std::string/*review id*/,ReviewBoardReview*> R2Rmap;
- + R2Rmap reviewid_to_review;
- + CReaderWriterLock guard;
- + typedef std::map<std::string,std::string> U2Bmap;
- + U2Bmap url_to_branch;
- + time_t lastupdate;
- + time_t Now();
- + time_t FromISO8601(const std::string& timestr);
- + std::string ToISO8601(time_t time);
- + int newreviews;
- +public:
- + std::wstring savefilename;
- + void GetAllNeededData_FirstPass(const char * from_time = 0);
- + void GetSpecificReviewData_SecondPass(const std::vector<std::string>& branches);
- + std::stringstream GetReviewUnifiedDiff(const char * review);
- + ~ReviewBoard();
- +
- + // need lock funcs
- + std::vector<ReviewBoardXmlDocument*> const * GetReadOnlyData();
- + void GetReadLock() { guard.AcquireReaderLock(); }
- + void ReleaseReadOnlyData();
- + bool IsUrlMonitored(const std::string& branch);
- + bool IsUrlMonitored(const std::wstring& url);
- + typedef std::map<std::wstring, ReviewBoardReview const *> WR2Rmap;
- + void GetReviewsForUrl(const std::wstring& url, WR2Rmap& vec);
- + int GetNewReviewsForUrl(const std::wstring& url);
- + int GetUnreadReviewsForUrl(const std::wstring& url);
- +
- + void DeleteReview(const std::string& rev);
- + void ReviewSetRead(const std::string& rev, bool read = true);
- + void ReviewsSetRead(const std::wstring& url);
- + void Load(const std::wstring& filepath = TEXT(""));
- + void Save(const std::wstring& filepath = TEXT(""));
- + void AddBranchToMonitor(const std::wstring& url);
- + void AddBranchToMonitor(const std::string& url, const std::string& branch);
- + void RemoveBranchToMonitor(const std::string& url);
- + void RemoveBranchToMonitor(const std::wstring& url);
- + int DoUpdate();
- + int GetUnreadReviews();
- +};
- +
- +#define gReviewBoard (*(Singleton<ReviewBoard>::GetInstance()))
- +#define gReviewBoard_Cleanup Singleton<ReviewBoard>::Cleanup()
- +
- +#endif
- Index: src/Singleton.h
- ===================================================================
- --- src/Singleton.h (revision 0)
- +++ src/Singleton.h (revision 0)
- @@ -0,0 +1,34 @@
- +#ifndef SINGLETON_H__
- +#define SINGLETON_H__
- +
- +
- +template<typename T>
- +class Singleton
- +{
- +private:
- + static T * _instance;
- + Singleton()
- + {
- + }
- +public:
- + static T * GetInstance()
- + {
- + if(!_instance)
- + {
- + _instance = new T();
- + }
- + return _instance;
- + }
- + static void Cleanup()
- + {
- + if(_instance)
- + {
- + delete _instance;
- + _instance = 0;
- + }
- + }
- +};
- +
- +template <typename T> T* Singleton<T>::_instance = 0;
- +
- +#endif
- Index: src/timesupport.cc
- ===================================================================
- --- src/timesupport.cc (revision 0)
- +++ src/timesupport.cc (revision 0)
- @@ -0,0 +1,248 @@
- +// Copyright 2009 Google Inc.
- +//
- +// Licensed under the Apache License, Version 2.0 (the "License");
- +// you may not use this file except in compliance with the License.
- +// You may obtain a copy of the License at
- +//
- +// http://www.apache.org/licenses/LICENSE-2.0
- +//
- +// Unless required by applicable law or agreed to in writing, software
- +// distributed under the License is distributed on an "AS IS" BASIS,
- +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- +// See the License for the specific language governing permissions and
- +// limitations under the License.
- +
- +
- +#include "stdafx.h"
- +
- +#include "timesupport.h"
- +
- +#include <time.h>
- +#include <ctype.h>
- +#include <string.h>
- +
- +#ifdef WIN32
- +// Implement strptime under windows
- +static const char* kWeekFull[] = {
- + "Sunday", "Monday", "Tuesday", "Wednesday",
- + "Thursday", "Friday", "Saturday"
- +};
- +
- +static const char* kWeekAbbr[] = {
- + "Sun", "Mon", "Tue", "Wed",
- + "Thu", "Fri", "Sat"
- +};
- +
- +static const char* kMonthFull[] = {
- + "January", "February", "March", "April", "May", "June",
- + "July", "August", "September", "October", "November", "December"
- +};
- +
- +static const char* kMonthAbbr[] = {
- + "Jan", "Feb", "Mar", "Apr", "May", "Jun",
- + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
- +};
- +
- +static const char* _parse_num(const char* s, int low, int high, int* value) {
- + const char* p = s;
- + for (*value = 0; *p != NULL && isdigit(*p); ++p) {
- + *value = (*value) * 10 + static_cast<int>(*p) - static_cast<int>('0');
- + }
- +
- + if (p == s || *value < low || *value > high) return NULL;
- + return p;
- +}
- +
- +static char* _strptime(const char *s, const char *format, struct tm *tm) {
- + while (*format != NULL && *s != NULL) {
- + if (*format != '%') {
- + if (*s != *format) return NULL;
- +
- + ++format;
- + ++s;
- + continue;
- + }
- +
- + ++format;
- + int len = 0;
- + switch (*format) {
- + // weekday name.
- + case 'a':
- + case 'A':
- + tm->tm_wday = -1;
- + for (int i = 0; i < 7; ++i) {
- + len = static_cast<int>(strlen(kWeekAbbr[i]));
- + if (strnicmp(kWeekAbbr[i], s, len) == 0) {
- + tm->tm_wday = i;
- + break;
- + }
- +
- + len = static_cast<int>(strlen(kWeekFull[i]));
- + if (strnicmp(kWeekFull[i], s, len) == 0) {
- + tm->tm_wday = i;
- + break;
- + }
- + }
- + if (tm->tm_wday == -1) return NULL;
- + s += len;
- + break;
- +
- + // month name.
- + case 'b':
- + case 'B':
- + case 'h':
- + tm->tm_mon = -1;
- + for (int i = 0; i < 12; ++i) {
- + len = static_cast<int>(strlen(kMonthAbbr[i]));
- + if (strnicmp(kMonthAbbr[i], s, len) == 0) {
- + tm->tm_mon = i;
- + break;
- + }
- +
- + len = static_cast<int>(strlen(kMonthFull[i]));
- + if (strnicmp(kMonthFull[i], s, len) == 0) {
- + tm->tm_mon = i;
- + break;
- + }
- + }
- + if (tm->tm_mon == -1) return NULL;
- + s += len;
- + break;
- +
- + // month [1, 12].
- + case 'm':
- + s = _parse_num(s, 1, 12, &tm->tm_mon);
- + if (s == NULL) return NULL;
- + --tm->tm_mon;
- + break;
- +
- + // day [1, 31].
- + case 'd':
- + case 'e':
- + s = _parse_num(s, 1, 31, &tm->tm_mday);
- + if (s == NULL) return NULL;
- + break;
- +
- + // hour [0, 23].
- + case 'H':
- + s = _parse_num(s, 0, 23, &tm->tm_hour);
- + if (s == NULL) return NULL;
- + break;
- +
- + // minute [0, 59]
- + case 'M':
- + s = _parse_num(s, 0, 59, &tm->tm_min);
- + if (s == NULL) return NULL;
- + break;
- +
- + // seconds [0, 60]. 60 is for leap year.
- + case 'S':
- + s = _parse_num(s, 0, 60, &tm->tm_sec);
- + if (s == NULL) return NULL;
- + break;
- +
- + // year [1900, 9999].
- + case 'Y':
- + s = _parse_num(s, 1900, 9999, &tm->tm_year);
- + if (s == NULL) return NULL;
- + tm->tm_year -= 1900;
- + break;
- +
- + // year [0, 99].
- + case 'y':
- + s = _parse_num(s, 0, 99, &tm->tm_year);
- + if (s == NULL) return NULL;
- + if (tm->tm_year <= 68) {
- + tm->tm_year += 100;
- + }
- + break;
- +
- + // arbitray whitespace.
- + case 't':
- + case 'n':
- + while (isspace(*s)) ++s;
- + break;
- +
- + // '%'.
- + case '%':
- + if (*s != '%') return NULL;
- + ++s;
- + break;
- +
- + // All the other format are not supported.
- + default:
- + return NULL;
- + }
- + ++format;
- + }
- +
- + if (*format != NULL) {
- + return NULL;
- + } else {
- + return const_cast<char*>(s);
- + }
- +}
- +
- +char* strptime(const char *buf, const char *fmt, struct tm *tm) {
- + return _strptime(buf, fmt, tm);
- +}
- +#endif // WIN32
- +
- +#if defined(__linux__) || defined(__unix__)
- +
- +time_t _mkgmtime(const struct tm *tm) {
- + // Month-to-day offset for non-leap-years.
- + static const int month_day[12] =
- + {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
- +
- + // Most of the calculation is easy; leap years are the main difficulty.
- + int month = tm->tm_mon % 12;
- + int year = tm->tm_year + tm->tm_mon / 12;
- + if (month < 0) { // Negative values % 12 are still negative.
- + month += 12;
- + --year;
- + }
- +
- + // This is the number of Februaries since 1900.
- + const int year_for_leap = (month > 1) ? year + 1 : year;
- +
- + time_t rt = tm->tm_sec // Seconds
- + + 60 * (tm->tm_min // Minute = 60 seconds
- + + 60 * (tm->tm_hour // Hour = 60 minutes
- + + 24 * (month_day[month] + tm->tm_mday - 1 // Day = 24 hours
- + + 365 * (year - 70) // Year = 365 days
- + + (year_for_leap - 69) / 4 // Every 4 years is leap...
- + - (year_for_leap - 1) / 100 // Except centuries...
- + + (year_for_leap + 299) / 400))); // Except 400s.
- + return rt < 0 ? -1 : rt;
- +}
- +
- +#endif
- +
- +bool ParseRfcTime(const char* buf, struct tm *tm) {
- + memset(tm, 0, sizeof(*tm));
- + return
- + strptime(buf, "%a, %e %b %Y %H:%M:%S", tm) || // RFC 822/1123
- + strptime(buf, "%a, %e-%b-%y %H:%M:%S", tm) || // RFC 850/1036
- + strptime(buf, "%a %b %e %H:%M:%S %Y", tm); // asctime()
- +}
- +
- +// Covert the time to W3C Datetime formats.
- +// See http://www.w3.org/TR/NOTE-datetime
- +const std::string FormatW3CTime(const time_t &time) {
- + char buffer[80];
- + strftime(buffer, 80,
- + "%Y-%m-%dT%H:%M:%SZ", // like 2001-12-31T23:59:59Z
- + gmtime(&time));
- + return buffer;
- +}
- +
- +std::string FormatHttpDate(time_t t) {
- + // Convert 'time_t' to struct tm (GMT)
- + tm* gmt_p = gmtime(&t);
- +
- + // Convert struct tm to HTTP-date string
- + char buff[256];
- + strftime(buff, sizeof(buff), "%a, %d %b %Y %H:%M:%S GMT", gmt_p);
- + return buff;
- +}
- Index: src/timesupport.h
- ===================================================================
- --- src/timesupport.h (revision 0)
- +++ src/timesupport.h (revision 0)
- @@ -0,0 +1,53 @@
- +// Copyright 2009 Google Inc.
- +//
- +// Licensed under the Apache License, Version 2.0 (the "License");
- +// you may not use this file except in compliance with the License.
- +// You may obtain a copy of the License at
- +//
- +// http://www.apache.org/licenses/LICENSE-2.0
- +//
- +// Unless required by applicable law or agreed to in writing, software
- +// distributed under the License is distributed on an "AS IS" BASIS,
- +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- +// See the License for the specific language governing permissions and
- +// limitations under the License.
- +
- +
- +// This files includes functions to support time related operations.
- +// It defines common functions, which are only available on platforms.
- +// It also provides functions to parse RFC times.
- +
- +#ifndef COMMON_TIMESUPPORT_H__
- +#define COMMON_TIMESUPPORT_H__
- +
- +#include <time.h>
- +#include <string>
- +
- +#ifdef WIN32
- +// Convert a string representation time to a time tm structure.
- +// It is the conversion function of strftime().
- +// Linux provides this function.
- +char *strptime(const char *buf, const char *fmt, struct tm *tm);
- +#endif
- +
- +#if defined(__linux__) || defined(__unix__)
- +// Convert GMT time to UTC time value.
- +// It is like mktime(), but interprets the fields as GMT rather than local.
- +// This is the inverse of gmtime().
- +// Windows provides this function.
- +time_t _mkgmtime(const struct tm *tm);
- +#endif
- +
- +// Tries various rfc's to convert a buffer to a struct tm.
- +// Warning: this function only handles a few cases and completely ignores
- +// time zones!
- +bool ParseRfcTime(const char* buf, struct tm *tm);
- +
- +// Covert the time to W3C Datetime formats.
- +// See http://www.w3.org/TR/NOTE-datetime
- +const std::string FormatW3CTime(const time_t &time);
- +
- +// A helper method used to format HttpDate.
- +std::string FormatHttpDate(time_t t);
- +
- +#endif // COMMON_TIMESUPPORT_H__
- Index: src/URLDlg.cpp
- ===================================================================
- --- src/URLDlg.cpp (revision 605)
- +++ src/URLDlg.cpp (working copy)
- @@ -31,6 +31,7 @@
- {
- sSCCS[0] = _T("SVN");
- sSCCS[1] = _T("Accurev");
- + reviewmonitored = false;
- }
- CURLDlg::~CURLDlg(void)
- @@ -68,6 +69,7 @@
- SetDlgItemText(*this, IDC_URLTOMONITORLABEL, _T("URL to monitor"));
- SetDlgItemText(*this, IDC_URLGROUP, _T("SVN repository settings"));
- ShowWindow(GetDlgItem(*this, IDC_ACCUREVREPO), SW_HIDE);
- + ShowWindow(GetDlgItem(*this, IDC_CHECKREVIEWS), SW_SHOW);
- SendMessage(GetDlgItem(*this, IDC_SCCSCOMBO), CB_SETCURSEL, (WPARAM)sccs, 0);
- break;
- @@ -77,6 +79,7 @@
- SetDlgItemText(*this, IDC_URLTOMONITORLABEL, _T("Accurev stream"));
- SetDlgItemText(*this, IDC_URLGROUP, _T("Accurev repository settings"));
- ShowWindow(GetDlgItem(*this, IDC_ACCUREVREPO), SW_SHOW);
- + ShowWindow(GetDlgItem(*this, IDC_CHECKREVIEWS), SW_HIDE);
- SendMessage(GetDlgItem(*this, IDC_SCCSCOMBO), CB_SETCURSEL, (WPARAM)sccs, 1);
- break;
- }
- @@ -103,6 +106,7 @@
- AddToolTip(IDC_URLTOMONITOR, _T("URL to the repository, or the SVNParentPath URL"));
- AddToolTip(IDC_SCCSCOMBO, _T("Source code control system to use"));
- AddToolTip(IDC_ACCUREVREPO, _T("Accurev repository name"));
- + AddToolTip(IDC_CHECKREVIEWS, _T("Check review requests for this repository"));
- AddToolTip(IDC_IGNORESELF, _T("If enabled, commits from you won't show a notification"));
- AddToolTip(IDC_SCRIPT, _T("enter here a command which gets called after new revisions were detected.\n\n%revision gets replaced with the new HEAD revision\n%url gets replaced with the url of the project\n%project gets replaced with the project name\n\nExample command line:\nTortoiseProc.exe /command:update /rev:%revision /path:\"path\\to\\working\\copy\""));
- AddToolTip(IDC_WEBDIFF, _T("URL to a web viewer\n%revision gets replaced with the new HEAD revision\n%url gets replaced with the url of the project\n%project gets replaced with the project name"));
- @@ -119,6 +123,7 @@
- AddToolTip(IDC_CHECKTIME, _T("Interval for repository update checks"));
- // initialize the controls
- + SendMessage(GetDlgItem(*this, IDC_CHECKREVIEWS), BM_SETCHECK, reviewmonitored ? BST_CHECKED : BST_UNCHECKED, NULL);
- SetDlgItemText(*this, IDC_ACCUREVREPO, info.accurevRepo.c_str());
- SetDlgItemText(*this, IDC_URLTOMONITOR, info.url.c_str());
- WCHAR buf[20];
- @@ -294,6 +299,8 @@
- info.noexecuteignored = !!SendMessage(GetDlgItem(*this, IDC_EXECUTEIGNORED), BM_GETCHECK, 0, NULL);
- + reviewmonitored = !!SendMessage(GetDlgItem(*this, IDC_CHECKREVIEWS), BM_GETCHECK, 0, NULL);
- +
- // make sure this entry gets checked again as soon as the next timer fires
- info.lastchecked = 0;
- }
- Index: src/URLDlg.h
- ===================================================================
- --- src/URLDlg.h (revision 605)
- +++ src/URLDlg.h (working copy)
- @@ -31,6 +31,8 @@
- ~CURLDlg(void);
- void SetInfo(const CUrlInfo * pURLInfo = NULL);
- + void SetReviewMonitored(bool b) { reviewmonitored = b; }
- + bool GetReviewMonitored() { return reviewmonitored; }
- CUrlInfo * GetInfo() {return &info;}
- void ClearForTemplate();
- @@ -49,4 +51,5 @@
- CUrlInfo info;
- AeroControlBase m_aerocontrols;
- wstring sSCCS[CUrlInfo::SCCS_LEN];
- + bool reviewmonitored;
- };
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement