예제 #1
0
void CEditPropExternals::OnBnClickedFindhead()
{
    CProgressDlg progDlg;
    progDlg.ShowModal(m_hWnd, TRUE);
    progDlg.SetTitle(IDS_EDITPROPS_PROG_FINDHEADTITLE);
    progDlg.SetLine(1, CString(MAKEINTRESOURCE(IDS_EDITPROPS_PROG_FINDHEADROOTS)));
    DWORD count = 0;
    DWORD total = (DWORD)m_externals.size()*4;
    SVN svn;
    svn.SetPromptParentWindow(m_hWnd);
    SVNInfo svnInfo;
    svnInfo.SetPromptParentWindow(m_hWnd);
    for (auto it = m_externals.begin(); it != m_externals.end(); ++it)
    {
        progDlg.SetProgress(count++, total);
        if (progDlg.HasUserCancelled())
            break;
        if (it->root.IsEmpty())
        {
            CTSVNPath p = it->path;
            p.AppendPathString(it->targetDir);
            it->root = svn.GetRepositoryRoot(p);
        }
    }

    progDlg.SetLine(1, CString(MAKEINTRESOURCE(IDS_EDITPROPS_PROG_FINDHEADREVS)));
    SVNLogHelper logHelper;
    for (auto it = m_externals.begin(); it != m_externals.end(); ++it)
    {
        progDlg.SetProgress(count, total);
        progDlg.SetLine(2, it->url, true);
        if (progDlg.HasUserCancelled())
            break;
        count += 4;
        if (!it->root.IsEmpty())
        {
            auto youngestRev = logHelper.GetYoungestRev(CTSVNPath(it->fullurl));
            if (!youngestRev.IsValid())
                it->headrev = svn.GetHEADRevision(CTSVNPath(it->fullurl), true);
            else
                it->headrev = youngestRev;
        }
    }
    progDlg.Stop();
    m_ExtList.Invalidate();
}
예제 #2
0
bool SVNDiff::ShowCompare( const CTSVNPath& url1, const SVNRev& rev1, const CTSVNPath& url2, const SVNRev& rev2, SVNRev peg, bool ignoreprops, const CString& options, bool ignoreancestry /*= false*/, bool blame /*= false*/, svn_node_kind_t nodekind /*= svn_node_unknown*/ )
{
    CTSVNPath tempfile;
    CString mimetype;
    CProgressDlg progDlg;
    progDlg.SetTitle(IDS_APPNAME);
    progDlg.SetTime(false);
    m_pSVN->SetAndClearProgressInfo(&progDlg);
    CAppUtils::DiffFlags diffFlags;
    diffFlags.ReadOnly().AlternativeTool(m_bAlternativeTool);

    if ((m_pSVN->PathIsURL(url1))||(!rev1.IsWorking())||(!url1.IsEquivalentTo(url2)))
    {
        // no working copy path!
        progDlg.ShowModeless(GetHWND());

        tempfile = CTempFiles::Instance().GetTempFilePath(false, url1);
        // first find out if the url points to a file or dir
        CString sRepoRoot;
        if ((nodekind != svn_node_dir)&&(nodekind != svn_node_file))
        {
            progDlg.SetLine(1, CString(MAKEINTRESOURCE(IDS_PROGRESS_INFO)));
            SVNInfo info;
            const SVNInfoData * data = info.GetFirstFileInfo(url1, (peg.IsValid() ? peg : m_headPeg), rev1, svn_depth_empty);
            if (data == NULL)
            {
                data = info.GetFirstFileInfo(url1, (peg.IsValid() ? peg : rev1), rev1, svn_depth_empty);
                if (data == NULL)
                {
                    data = info.GetFirstFileInfo(url1, (peg.IsValid() ? peg : rev2), rev1, svn_depth_empty);
                    if (data == NULL)
                    {
                        progDlg.Stop();
                        m_pSVN->SetAndClearProgressInfo((HWND)NULL);
                        info.ShowErrorDialog(GetHWND());
                        return false;
                    }
                    else
                    {
                        sRepoRoot = data->reposRoot;
                        nodekind = data->kind;
                        peg = peg.IsValid() ? peg : rev2;
                    }
                }
                else
                {
                    sRepoRoot = data->reposRoot;
                    nodekind = data->kind;
                    peg = peg.IsValid() ? peg : rev1;
                }
            }
            else
            {
                sRepoRoot = data->reposRoot;
                nodekind = data->kind;
                peg = peg.IsValid() ? peg : m_headPeg;
            }
        }
        else
        {
            sRepoRoot = m_pSVN->GetRepositoryRoot(url1);
            peg = peg.IsValid() ? peg : m_headPeg;
        }
        if (nodekind == svn_node_dir)
        {
            if (rev1.IsWorking())
            {
                if (UnifiedDiff(tempfile, url1, rev1, url2, rev2, (peg.IsValid() ? peg : SVNRev::REV_WC), options))
                {
                    CString sWC;
                    sWC.LoadString(IDS_DIFF_WORKINGCOPY);
                    progDlg.Stop();
                    m_pSVN->SetAndClearProgressInfo((HWND)NULL);
                    return !!CAppUtils::StartExtPatch(tempfile, url1.GetDirectory(), sWC, url2.GetSVNPathString(), TRUE);
                }
            }
            else
            {
                progDlg.Stop();
                m_pSVN->SetAndClearProgressInfo((HWND)NULL);
                CFileDiffDlg fdlg;
                fdlg.DoBlame(blame);
                if (url1.IsEquivalentTo(url2))
                {
                    fdlg.SetDiff(url1, (peg.IsValid() ? peg : m_headPeg), rev1, rev2, svn_depth_infinity, ignoreancestry);
                    fdlg.DoModal();
                }
                else
                {
                    fdlg.SetDiff(url1, rev1, url2, rev2, svn_depth_infinity, ignoreancestry);
                    fdlg.DoModal();
                }
            }
        }
        else
        {
            if (url1.IsEquivalentTo(url2) && !ignoreprops)
            {
                svn_revnum_t baseRev = 0;
                DiffProps(url1, rev2, rev1, baseRev);
            }
            // diffing two revs of a file, so export two files
            CTSVNPath tempfile1 = CTempFiles::Instance().GetTempFilePath(m_bRemoveTempFiles, blame ? CTSVNPath() : url1, rev1);
            CTSVNPath tempfile2 = CTempFiles::Instance().GetTempFilePath(m_bRemoveTempFiles, blame ? CTSVNPath() : url2, rev2);

            m_pSVN->SetAndClearProgressInfo(&progDlg, true);    // activate progress bar
            progDlg.FormatPathLine(1, IDS_PROGRESSGETFILEREVISION, (LPCTSTR)url1.GetUIFileOrDirectoryName(), (LPCTSTR)rev1.ToString());
            CAppUtils::GetMimeType(url1, mimetype, rev1);
            CBlame blamer;
            blamer.SetAndClearProgressInfo(&progDlg, true);
            if (blame)
            {
                if (!blamer.BlameToFile(url1, 1, rev1, peg.IsValid() ? peg : rev1, tempfile1, options, TRUE, TRUE))
                {
                    if ((peg.IsValid())&&(blamer.GetSVNError()->apr_err != SVN_ERR_CLIENT_IS_BINARY_FILE))
                    {
                        if (!blamer.BlameToFile(url1, 1, rev1, rev1, tempfile1, options, TRUE, TRUE))
                        {
                            progDlg.Stop();
                            m_pSVN->SetAndClearProgressInfo((HWND)NULL);
                            blamer.ShowErrorDialog(GetHWND());
                            return false;
                        }
                    }
                    else
                    {
                        if (blamer.GetSVNError()->apr_err != SVN_ERR_CLIENT_IS_BINARY_FILE)
                        {
                            progDlg.Stop();
                            m_pSVN->SetAndClearProgressInfo((HWND)NULL);
                        }
                        blamer.ShowErrorDialog(GetHWND());
                        if (blamer.GetSVNError()->apr_err == SVN_ERR_CLIENT_IS_BINARY_FILE)
                            blame = false;
                        else
                            return false;
                    }
                }
            }
            if (!blame)
            {
                bool tryWorking = (!m_pSVN->PathIsURL(url1) && rev1.IsWorking() && PathFileExists(url1.GetWinPath()));
                if (!m_pSVN->Export(url1, tempfile1, peg.IsValid() && !tryWorking ? peg : rev1, rev1))
                {
                    if (peg.IsValid())
                    {
                        if (!m_pSVN->Export(url1, tempfile1, rev1, rev1))
                        {
                            progDlg.Stop();
                            m_pSVN->SetAndClearProgressInfo((HWND)NULL);
                            m_pSVN->ShowErrorDialog(GetHWND());
                            return false;
                        }
                    }
                    else
                    {
                        progDlg.Stop();
                        m_pSVN->SetAndClearProgressInfo((HWND)NULL);
                        m_pSVN->ShowErrorDialog(GetHWND());
                        return false;
                    }
                }
            }
            SetFileAttributes(tempfile1.GetWinPath(), FILE_ATTRIBUTE_READONLY);

            progDlg.FormatPathLine(1, IDS_PROGRESSGETFILEREVISION, (LPCTSTR)url2.GetUIFileOrDirectoryName(), (LPCTSTR)rev2.ToString());
            progDlg.SetProgress(50,100);
            if (blame)
            {
                if (!blamer.BlameToFile(url2, 1, rev2, peg.IsValid() ? peg : rev2, tempfile2, options, TRUE, TRUE))
                {
                    if (peg.IsValid())
                    {
                        if (!blamer.BlameToFile(url2, 1, rev2, rev2, tempfile2, options, TRUE, TRUE))
                        {
                            progDlg.Stop();
                            m_pSVN->SetAndClearProgressInfo((HWND)NULL);
                            m_pSVN->ShowErrorDialog(GetHWND());
                            return false;
                        }
                    }
                    else
                    {
                        progDlg.Stop();
                        m_pSVN->SetAndClearProgressInfo((HWND)NULL);
                        m_pSVN->ShowErrorDialog(GetHWND());
                        return false;
                    }
                }
            }
            else
            {
                if (!m_pSVN->Export(url2, tempfile2, peg.IsValid() ? peg : rev2, rev2))
                {
                    if (peg.IsValid())
                    {
                        if (!m_pSVN->Export(url2, tempfile2, rev2, rev2))
                        {
                            progDlg.Stop();
                            m_pSVN->SetAndClearProgressInfo((HWND)NULL);
                            m_pSVN->ShowErrorDialog(GetHWND());
                            return false;
                        }
                    }
                    else
                    {
                        progDlg.Stop();
                        m_pSVN->SetAndClearProgressInfo((HWND)NULL);
                        m_pSVN->ShowErrorDialog(GetHWND());
                        return false;
                    }
                }
            }
            SetFileAttributes(tempfile2.GetWinPath(), FILE_ATTRIBUTE_READONLY);

            progDlg.SetProgress(100,100);
            progDlg.Stop();
            m_pSVN->SetAndClearProgressInfo((HWND)NULL);

            CString revname1, revname2;
            if (url1.IsEquivalentTo(url2))
            {
                revname1.Format(L"%s Revision %s", (LPCTSTR)url1.GetUIFileOrDirectoryName(), (LPCTSTR)rev1.ToString());
                revname2.Format(L"%s Revision %s", (LPCTSTR)url2.GetUIFileOrDirectoryName(), (LPCTSTR)rev2.ToString());
            }
            else
            {
                if (sRepoRoot.IsEmpty())
                {
                    revname1.Format(L"%s Revision %s", (LPCTSTR)url1.GetSVNPathString(), (LPCTSTR)rev1.ToString());
                    revname2.Format(L"%s Revision %s", (LPCTSTR)url2.GetSVNPathString(), (LPCTSTR)rev2.ToString());
                }
                else
                {
                    if (url1.IsUrl())
                        revname1.Format(L"%s Revision %s", (LPCTSTR)url1.GetSVNPathString().Mid(sRepoRoot.GetLength()), (LPCTSTR)rev1.ToString());
                    else
                        revname1.Format(L"%s Revision %s", (LPCTSTR)url1.GetSVNPathString(), (LPCTSTR)rev1.ToString());
                    if (url2.IsUrl() && (url2.GetSVNPathString().Left(sRepoRoot.GetLength()).Compare(sRepoRoot) == 0))
                        revname2.Format(L"%s Revision %s", (LPCTSTR)url2.GetSVNPathString().Mid(sRepoRoot.GetLength()), (LPCTSTR)rev2.ToString());
                    else
                        revname2.Format(L"%s Revision %s", (LPCTSTR)url2.GetSVNPathString(), (LPCTSTR)rev2.ToString());
                }
            }
            return CAppUtils::StartExtDiff(tempfile1, tempfile2, revname1, revname2, url1, url2, rev1, rev2, peg, diffFlags.Blame(blame), m_JumpLine, L"", mimetype);
        }
    }
    else
    {
        // compare with working copy
        if (PathIsDirectory(url1.GetWinPath()))
        {
            if (UnifiedDiff(tempfile, url1, rev1, url1, rev2, (peg.IsValid() ? peg : SVNRev::REV_WC), options))
            {
                CString sWC, sRev;
                sWC.LoadString(IDS_DIFF_WORKINGCOPY);
                sRev.Format(IDS_DIFF_REVISIONPATCHED, (LONG)rev2);
                progDlg.Stop();
                m_pSVN->SetAndClearProgressInfo((HWND)NULL);
                return !!CAppUtils::StartExtPatch(tempfile, url1.GetDirectory(), sWC, sRev, TRUE);
            }
        }
        else
        {
            ASSERT(rev1.IsWorking());

            if (url1.IsEquivalentTo(url2) && !ignoreprops)
            {
                svn_revnum_t baseRev = 0;
                DiffProps(url1, rev1, rev2, baseRev);
            }

            m_pSVN->SetAndClearProgressInfo(&progDlg, true);    // activate progress bar
            progDlg.ShowModeless(GetHWND());
            progDlg.FormatPathLine(1, IDS_PROGRESSGETFILEREVISION, (LPCTSTR)url1.GetUIFileOrDirectoryName(), (LPCTSTR)rev2.ToString());

            tempfile = CTempFiles::Instance().GetTempFilePath(m_bRemoveTempFiles, url1, rev2);
            if (blame)
            {
                CBlame blamer;
                if (!blamer.BlameToFile(url1, 1, rev2, (peg.IsValid() ? peg : SVNRev::REV_WC), tempfile, options, TRUE, TRUE))
                {
                    if (peg.IsValid())
                    {
                        if (!blamer.BlameToFile(url1, 1, rev2, SVNRev::REV_WC, tempfile, options, TRUE, TRUE))
                        {
                            progDlg.Stop();
                            m_pSVN->SetAndClearProgressInfo((HWND)NULL);
                            m_pSVN->ShowErrorDialog(GetHWND());
                            return false;
                        }
                    }
                    else
                    {
                        progDlg.Stop();
                        m_pSVN->SetAndClearProgressInfo((HWND)NULL);
                        m_pSVN->ShowErrorDialog(GetHWND());
                        return false;
                    }
                }
                progDlg.Stop();
                m_pSVN->SetAndClearProgressInfo((HWND)NULL);
                SetFileAttributes(tempfile.GetWinPath(), FILE_ATTRIBUTE_READONLY);
                CTSVNPath tempfile2 = CTempFiles::Instance().GetTempFilePath(false, url1);
                if (!blamer.BlameToFile(url1, 1, SVNRev::REV_WC, SVNRev::REV_WC, tempfile2, options, TRUE, TRUE))
                {
                    progDlg.Stop();
                    m_pSVN->SetAndClearProgressInfo((HWND)NULL);
                    m_pSVN->ShowErrorDialog(GetHWND());
                    return false;
                }
                CString revname, wcname;
                revname.Format(L"%s Revision %ld", (LPCTSTR)url1.GetFilename(), (LONG)rev2);
                wcname.Format(IDS_DIFF_WCNAME, (LPCTSTR)url1.GetFilename());
                m_pSVN->SetAndClearProgressInfo((HWND)NULL);
                return CAppUtils::StartExtDiff(tempfile, tempfile2, revname, wcname, url1, url2, rev1, rev2, peg, diffFlags, m_JumpLine, url1.GetFileOrDirectoryName(), L"");
            }
            else
            {
                if (!m_pSVN->Export(url1, tempfile, (peg.IsValid() ? peg : SVNRev::REV_WC), rev2))
                {
                    if (peg.IsValid())
                    {
                        if (!m_pSVN->Export(url1, tempfile, SVNRev::REV_WC, rev2))
                        {
                            progDlg.Stop();
                            m_pSVN->SetAndClearProgressInfo((HWND)NULL);
                            m_pSVN->ShowErrorDialog(GetHWND());
                            return false;
                        }
                    }
                    else
                    {
                        progDlg.Stop();
                        m_pSVN->SetAndClearProgressInfo((HWND)NULL);
                        m_pSVN->ShowErrorDialog(GetHWND());
                        return false;
                    }
                }
                progDlg.Stop();
                m_pSVN->SetAndClearProgressInfo((HWND)NULL);
                SetFileAttributes(tempfile.GetWinPath(), FILE_ATTRIBUTE_READONLY);
                CString revname, wcname;
                revname.Format(L"%s Revision %s", (LPCTSTR)url1.GetFilename(), (LPCTSTR)rev2.ToString());
                wcname.Format(IDS_DIFF_WCNAME, (LPCTSTR)url1.GetFilename());
                return CAppUtils::StartExtDiff(tempfile, url1, revname, wcname, url1, url1, rev2, rev1, peg, diffFlags, m_JumpLine, url1.GetFileOrDirectoryName(), L"");
            }
        }
    }
    m_pSVN->SetAndClearProgressInfo((HWND)NULL);
    return false;
}
예제 #3
0
bool SVNDiff::DiffFileAgainstBase( const CTSVNPath& filePath, svn_revnum_t & baseRev, bool ignoreprops, svn_wc_status_kind status /*= svn_wc_status_none*/, svn_wc_status_kind text_status /*= svn_wc_status_none*/, svn_wc_status_kind prop_status /*= svn_wc_status_none*/ )
{
    bool retvalue = false;
    bool fileexternal = false;
    if ((text_status == svn_wc_status_none)||(prop_status == svn_wc_status_none))
    {
        SVNStatus stat;
        stat.GetStatus(filePath);
        if (stat.status == NULL)
            return false;
        text_status = stat.status->text_status;
        prop_status = stat.status->prop_status;
        fileexternal = stat.status->file_external != 0;
    }
    if (!ignoreprops && (prop_status > svn_wc_status_normal))
    {
        DiffProps(filePath, SVNRev::REV_WC, SVNRev::REV_BASE, baseRev);
    }

    if (filePath.IsDirectory())
        return true;
    if ((status >= svn_wc_status_normal) || (text_status >= svn_wc_status_normal))
    {
        CTSVNPath basePath(SVN::GetPristinePath(filePath));
        if (baseRev == 0)
        {
            SVNInfo info;
            const SVNInfoData * infodata = info.GetFirstFileInfo(filePath, SVNRev(), SVNRev());

            if (infodata)
            {
                if (infodata->copyfromurl && infodata->copyfromurl[0])
                    baseRev = infodata->copyfromrev;
                else
                    baseRev = infodata->lastchangedrev;
            }
        }
        // If necessary, convert the line-endings on the file before diffing
        // note: file externals can not be exported
        if (((DWORD)CRegDWORD(L"Software\\TortoiseSVN\\ConvertBase", TRUE)) && (!fileexternal))
        {
            CTSVNPath temporaryFile = CTempFiles::Instance().GetTempFilePath(m_bRemoveTempFiles, filePath, SVNRev::REV_BASE);
            if (!m_pSVN->Export(filePath, temporaryFile, SVNRev(SVNRev::REV_BASE), SVNRev(SVNRev::REV_BASE)))
            {
                temporaryFile.Reset();
            }
            else
            {
                basePath = temporaryFile;
                SetFileAttributes(basePath.GetWinPath(), FILE_ATTRIBUTE_READONLY);
            }
        }
        // for added/deleted files, we don't have a BASE file.
        // create an empty temp file to be used.
        if (!basePath.Exists())
        {
            basePath = CTempFiles::Instance().GetTempFilePath(m_bRemoveTempFiles, filePath, SVNRev::REV_BASE);
            SetFileAttributes(basePath.GetWinPath(), FILE_ATTRIBUTE_READONLY);
        }
        CString name = filePath.GetFilename();
        CTSVNPath wcFilePath = filePath;
        if (!wcFilePath.Exists())
        {
            wcFilePath = CTempFiles::Instance().GetTempFilePath(m_bRemoveTempFiles, filePath, SVNRev::REV_BASE);
            SetFileAttributes(wcFilePath.GetWinPath(), FILE_ATTRIBUTE_READONLY);
        }
        CString n1, n2;
        n1.Format(IDS_DIFF_WCNAME, (LPCTSTR)name);
        if (baseRev)
            n2.FormatMessage(IDS_DIFF_BASENAMEREV, (LPCTSTR)name, baseRev);
        else
            n2.Format(IDS_DIFF_BASENAME, (LPCTSTR)name);
        retvalue = CAppUtils::StartExtDiff(
            basePath, wcFilePath, n2, n1,
            filePath, filePath, SVNRev::REV_BASE, SVNRev::REV_WC, SVNRev::REV_BASE,
            CAppUtils::DiffFlags().Wait().AlternativeTool(m_bAlternativeTool), m_JumpLine, name, L"");
    }
    return retvalue;
}
예제 #4
0
void CEditPropExternals::OnContextMenu(CWnd* /*pWnd*/, CPoint point)
{
    int selIndex = m_ExtList.GetSelectionMark();
    if (selIndex < 0)
        return; // nothing selected, nothing to do with a context menu
    int selCount = m_ExtList.GetSelectedCount();
    if (selCount <= 0)
        return; // nothing selected, nothing to do with a context menu

    // if the context menu is invoked through the keyboard, we have to use
    // a calculated position on where to anchor the menu on
    if ((point.x == -1) && (point.y == -1))
    {
        CRect rect;
        m_ExtList.GetItemRect(selIndex, &rect, LVIR_LABEL);
        m_ExtList.ClientToScreen(&rect);
        point = rect.CenterPoint();
    }

    bool haveHead = true;

    POSITION pos = m_ExtList.GetFirstSelectedItemPosition();
    while (pos)
    {
        int index = m_ExtList.GetNextSelectedItem(pos);
        if ((index >= 0)&&(index < (int)m_externals.size()))
        {
            if (m_externals[index].headrev == SVN_INVALID_REVNUM)
            {
                haveHead = false;
                break;
            }
        }
    }

    CIconMenu popup;
    if (popup.CreatePopupMenu())
    {
        if (haveHead)
            popup.AppendMenuIcon(CMD_ADJUST, IDS_EDITPROPS_ADJUST_TO_HEAD);
        else
            popup.AppendMenuIcon(CMD_FETCH_AND_ADJUST, IDS_EDITPROPS_FETCH_AND_ADJUST_TO_HEAD);

        int cmd = popup.TrackPopupMenu(TPM_RETURNCMD | TPM_LEFTALIGN | TPM_NONOTIFY | TPM_RIGHTBUTTON, point.x, point.y, this, 0);

        switch (cmd)
        {
        case CMD_FETCH_AND_ADJUST:
            {
                SVN svn;
                svn.SetPromptParentWindow(m_hWnd);
                SVNInfo svnInfo;
                svnInfo.SetPromptParentWindow(m_hWnd);
                SVNLogHelper logHelper;
                CProgressDlg progDlg;
                progDlg.ShowModal(m_hWnd, TRUE);
                progDlg.SetTitle(IDS_EDITPROPS_PROG_FINDHEADTITLE);
                progDlg.SetLine(1, CString(MAKEINTRESOURCE(IDS_EDITPROPS_PROG_FINDHEADREVS)));
                DWORD count = 0;
                DWORD total = m_ExtList.GetSelectedCount();
                POSITION p = m_ExtList.GetFirstSelectedItemPosition();
                while (p)
                {
                    int index = m_ExtList.GetNextSelectedItem(p);
                    progDlg.SetProgress(count++, total);
                    if ((index >= 0)&&(index < (int)m_externals.size()))
                    {
                        progDlg.SetLine(2, m_externals[index].url, true);
                        if (m_externals[index].headrev == SVN_INVALID_REVNUM)
                        {
                            if (m_externals[index].root.IsEmpty())
                            {
                                CTSVNPath path_ = m_externals[index].path;
                                path_.AppendPathString(m_externals[index].targetDir);
                                m_externals[index].root = svn.GetRepositoryRoot(path_);
                            }
                            auto fullurl = CTSVNPath(m_externals[index].fullurl);
                            auto youngestRev = logHelper.GetYoungestRev(fullurl);
                            if (!youngestRev.IsValid())
                                m_externals[index].headrev = svn.GetHEADRevision(fullurl, true);
                            else
                                m_externals[index].headrev = youngestRev;
                        }
                    }
                }
                progDlg.Stop();
            }
            // intentional fall through
        case CMD_ADJUST:
            {
                POSITION p = m_ExtList.GetFirstSelectedItemPosition();
                while (p)
                {
                    int index = m_ExtList.GetNextSelectedItem(p);
                    if ((index >= 0)&&(index < (int)m_externals.size()))
                    {
                        if (m_externals[index].headrev != SVN_INVALID_REVNUM)
                        {
                            if (m_externals[index].revision.kind == svn_opt_revision_number)
                            {
                                m_externals[index].revision.value.number = -1;
                                m_externals[index].revision.kind = svn_opt_revision_unspecified;
                            }
                            m_externals[index].pegrevision.value.number = m_externals[index].headrev;
                            m_externals[index].pegrevision.kind = svn_opt_revision_number;
                        }
                    }
                }
                m_ExtList.Invalidate();
            }
            break;
        }
    }
}
예제 #5
0
bool ConflictEditorCommand::Execute()
{
	CTSVNPath merge = cmdLinePath;
	CTSVNPath directory = merge.GetDirectory();
	bool bRet = false;
	bool bAlternativeTool = !!parser.HasKey(_T("alternative"));

	// we have the conflicted file (%merged)
	// now look for the other required files
	SVNStatus stat;
	stat.GetStatus(merge);
	if (stat.status == NULL)
		return false;

	if (stat.status->text_status == svn_wc_status_conflicted)
	{
		// we have a text conflict, use our merge tool to resolve the conflict

		CTSVNPath theirs(directory);
		CTSVNPath mine(directory);
		CTSVNPath base(directory);
		bool bConflictData = false;

		if ((stat.status->entry)&&(stat.status->entry->conflict_new))
		{
			theirs.AppendPathString(CUnicodeUtils::GetUnicode(stat.status->entry->conflict_new));
			bConflictData = true;
		}
		if ((stat.status->entry)&&(stat.status->entry->conflict_old))
		{
			base.AppendPathString(CUnicodeUtils::GetUnicode(stat.status->entry->conflict_old));
			bConflictData = true;
		}
		if ((stat.status->entry)&&(stat.status->entry->conflict_wrk))
		{
			mine.AppendPathString(CUnicodeUtils::GetUnicode(stat.status->entry->conflict_wrk));
			bConflictData = true;
		}
		else
		{
			mine = merge;
		}
		if (bConflictData)
			bRet = !!CAppUtils::StartExtMerge(CAppUtils::MergeFlags().AlternativeTool(bAlternativeTool), 
												base, theirs, mine, merge);
	}

	if (stat.status->prop_status == svn_wc_status_conflicted)
	{
		// we have a property conflict
		CTSVNPath prej(directory);
		if ((stat.status->entry)&&(stat.status->entry->prejfile))
		{
			prej.AppendPathString(CUnicodeUtils::GetUnicode(stat.status->entry->prejfile));
			// there's a problem: the prej file contains a _description_ of the conflict, and
			// that description string might be translated. That means we have no way of parsing
			// the file to find out the conflicting values.
			// The only thing we can do: show a dialog with the conflict description, then
			// let the user either accept the existing property or open the property edit dialog
			// to manually change the properties and values. And a button to mark the conflict as
			// resolved.
			CEditPropConflictDlg dlg;
			dlg.SetPrejFile(prej);
			dlg.SetConflictedItem(merge);
			bRet = (dlg.DoModal() != IDCANCEL);
		}
	}

	if (stat.status->tree_conflict)
	{
		// we have a tree conflict
		SVNInfo info;
		const SVNInfoData * pInfoData = info.GetFirstFileInfo(merge, SVNRev(), SVNRev());
		if (pInfoData)
		{
			if (pInfoData->treeconflict_kind == svn_wc_conflict_kind_text)
			{
				CTSVNPath theirs(directory);
				CTSVNPath mine(directory);
				CTSVNPath base(directory);
				bool bConflictData = false;

				if (pInfoData->treeconflict_theirfile)
				{
					theirs.AppendPathString(pInfoData->treeconflict_theirfile);
					bConflictData = true;
				}
				if (pInfoData->treeconflict_basefile)
				{
					base.AppendPathString(pInfoData->treeconflict_basefile);
					bConflictData = true;
				}
				if (pInfoData->treeconflict_myfile)
				{
					mine.AppendPathString(pInfoData->treeconflict_myfile);
					bConflictData = true;
				}
				else
				{
					mine = merge;
				}
				if (bConflictData)
					bRet = !!CAppUtils::StartExtMerge(CAppUtils::MergeFlags().AlternativeTool(bAlternativeTool),
														base, theirs, mine, merge);
			}
			else if (pInfoData->treeconflict_kind == svn_wc_conflict_kind_tree)
			{
				CString sConflictAction;
				CString sConflictReason;
				CString sResolveTheirs;
				CString sResolveMine;
				CTSVNPath treeConflictPath = CTSVNPath(pInfoData->treeconflict_path);
				CString sItemName = treeConflictPath.GetUIFileOrDirectoryName();
				
				if (pInfoData->treeconflict_nodekind == svn_node_file)
				{
					switch (pInfoData->treeconflict_operation)
					{
					default:
					case svn_wc_operation_none:
					case svn_wc_operation_update:
						switch (pInfoData->treeconflict_action)
						{
						default:
						case svn_wc_conflict_action_edit:
							sConflictAction.Format(IDS_TREECONFLICT_FILEUPDATEEDIT, (LPCTSTR)sItemName);
							sResolveTheirs.LoadString(IDS_TREECONFLICT_RESOLVE_KEEPREPOSITORYFILE);
							break;
						case svn_wc_conflict_action_add:
							sConflictAction.Format(IDS_TREECONFLICT_FILEUPDATEADD, (LPCTSTR)sItemName);
							sResolveTheirs.LoadString(IDS_TREECONFLICT_RESOLVE_KEEPREPOSITORYFILE);
							break;
						case svn_wc_conflict_action_delete:
							sConflictAction.Format(IDS_TREECONFLICT_FILEUPDATEDELETE, (LPCTSTR)sItemName);
							sResolveTheirs.LoadString(IDS_TREECONFLICT_RESOLVE_REMOVEFILE);
							break;
						}
						break;
					case svn_wc_operation_switch:
						switch (pInfoData->treeconflict_action)
						{
						default:
						case svn_wc_conflict_action_edit:
							sConflictAction.Format(IDS_TREECONFLICT_FILESWITCHEDIT, (LPCTSTR)sItemName);
							sResolveTheirs.LoadString(IDS_TREECONFLICT_RESOLVE_KEEPREPOSITORYFILE);
							break;
						case svn_wc_conflict_action_add:
							sConflictAction.Format(IDS_TREECONFLICT_FILESWITCHADD, (LPCTSTR)sItemName);
							sResolveTheirs.LoadString(IDS_TREECONFLICT_RESOLVE_KEEPREPOSITORYFILE);
							break;
						case svn_wc_conflict_action_delete:
							sConflictAction.Format(IDS_TREECONFLICT_FILESWITCHDELETE, (LPCTSTR)sItemName);
							sResolveTheirs.LoadString(IDS_TREECONFLICT_RESOLVE_REMOVEFILE);
							break;
						}
						break;
					case svn_wc_operation_merge:
						switch (pInfoData->treeconflict_action)
						{
						default:
						case svn_wc_conflict_action_edit:
							sConflictAction.Format(IDS_TREECONFLICT_FILEMERGEEDIT, (LPCTSTR)sItemName);
							sResolveTheirs.LoadString(IDS_TREECONFLICT_RESOLVE_KEEPREPOSITORYFILE);
							break;
						case svn_wc_conflict_action_add:
							sConflictAction.Format(IDS_TREECONFLICT_FILEMERGEADD, (LPCTSTR)sItemName);
							sResolveTheirs.LoadString(IDS_TREECONFLICT_RESOLVE_KEEPREPOSITORYFILE);
							break;
						case svn_wc_conflict_action_delete:
							sConflictAction.Format(IDS_TREECONFLICT_FILEMERGEDELETE, (LPCTSTR)sItemName);
							sResolveTheirs.LoadString(IDS_TREECONFLICT_RESOLVE_REMOVEFILE);
							break;
						}
						break;
					}
				}
				else //if (pInfoData->treeconflict_nodekind == svn_node_dir)
				{
					switch (pInfoData->treeconflict_operation)
					{
					default:
					case svn_wc_operation_none:
					case svn_wc_operation_update:
						switch (pInfoData->treeconflict_action)
						{
						default:
						case svn_wc_conflict_action_edit:
							sConflictAction.Format(IDS_TREECONFLICT_DIRUPDATEEDIT, (LPCTSTR)sItemName);
							sResolveTheirs.LoadString(IDS_TREECONFLICT_RESOLVE_KEEPREPOSITORYDIR);
							break;
						case svn_wc_conflict_action_add:
							sConflictAction.Format(IDS_TREECONFLICT_DIRUPDATEADD, (LPCTSTR)sItemName);
							sResolveTheirs.LoadString(IDS_TREECONFLICT_RESOLVE_KEEPREPOSITORYDIR);
							break;
						case svn_wc_conflict_action_delete:
							sConflictAction.Format(IDS_TREECONFLICT_DIRUPDATEDELETE, (LPCTSTR)sItemName);
							sResolveTheirs.LoadString(IDS_TREECONFLICT_RESOLVE_REMOVEDIR);
							break;
						}
						break;
					case svn_wc_operation_switch:
						switch (pInfoData->treeconflict_action)
						{
						default:
						case svn_wc_conflict_action_edit:
							sConflictAction.Format(IDS_TREECONFLICT_DIRSWITCHEDIT, (LPCTSTR)sItemName);
							sResolveTheirs.LoadString(IDS_TREECONFLICT_RESOLVE_KEEPREPOSITORYDIR);
							break;
						case svn_wc_conflict_action_add:
							sConflictAction.Format(IDS_TREECONFLICT_DIRSWITCHADD, (LPCTSTR)sItemName);
							sResolveTheirs.LoadString(IDS_TREECONFLICT_RESOLVE_KEEPREPOSITORYDIR);
							break;
						case svn_wc_conflict_action_delete:
							sConflictAction.Format(IDS_TREECONFLICT_DIRSWITCHDELETE, (LPCTSTR)sItemName);
							sResolveTheirs.LoadString(IDS_TREECONFLICT_RESOLVE_REMOVEDIR);
							break;
						}
						break;
					case svn_wc_operation_merge:
						switch (pInfoData->treeconflict_action)
						{
						default:
						case svn_wc_conflict_action_edit:
							sConflictAction.Format(IDS_TREECONFLICT_DIRMERGEEDIT, (LPCTSTR)sItemName);
							sResolveTheirs.LoadString(IDS_TREECONFLICT_RESOLVE_KEEPREPOSITORYDIR);
							break;
						case svn_wc_conflict_action_add:
							sConflictAction.Format(IDS_TREECONFLICT_DIRMERGEADD, (LPCTSTR)sItemName);
							sResolveTheirs.LoadString(IDS_TREECONFLICT_RESOLVE_KEEPREPOSITORYDIR);
							break;
						case svn_wc_conflict_action_delete:
							sConflictAction.Format(IDS_TREECONFLICT_DIRMERGEDELETE, (LPCTSTR)sItemName);
							sResolveTheirs.LoadString(IDS_TREECONFLICT_RESOLVE_REMOVEDIR);
							break;
						}
						break;
					}
				}

				UINT uReasonID = 0;
				switch (pInfoData->treeconflict_reason)
				{ 
				case svn_wc_conflict_reason_edited:
					uReasonID = IDS_TREECONFLICT_REASON_EDITED;
					sResolveMine.LoadString(pInfoData->treeconflict_nodekind == svn_node_dir ? IDS_TREECONFLICT_RESOLVE_KEEPLOCALDIR : IDS_TREECONFLICT_RESOLVE_KEEPLOCALFILE);
					break;
				case svn_wc_conflict_reason_obstructed:
					uReasonID = IDS_TREECONFLICT_REASON_OBSTRUCTED;
					sResolveMine.LoadString(pInfoData->treeconflict_nodekind == svn_node_dir ? IDS_TREECONFLICT_RESOLVE_KEEPLOCALDIR : IDS_TREECONFLICT_RESOLVE_KEEPLOCALFILE);
					break;
				case svn_wc_conflict_reason_deleted:
					uReasonID = IDS_TREECONFLICT_REASON_DELETED;
					sResolveMine.LoadString(IDS_TREECONFLICT_RESOLVE_MARKASRESOLVED);
					break;
				case svn_wc_conflict_reason_added:
					uReasonID = IDS_TREECONFLICT_REASON_ADDED;
					sResolveMine.LoadString(pInfoData->treeconflict_nodekind == svn_node_dir ? IDS_TREECONFLICT_RESOLVE_KEEPLOCALDIR : IDS_TREECONFLICT_RESOLVE_KEEPLOCALFILE);
					break;
				case svn_wc_conflict_reason_missing:
					uReasonID = IDS_TREECONFLICT_REASON_MISSING;
					sResolveMine.LoadString(IDS_TREECONFLICT_RESOLVE_MARKASRESOLVED);
					break;
				case svn_wc_conflict_reason_unversioned:
					uReasonID = IDS_TREECONFLICT_REASON_UNVERSIONED;
					sResolveMine.LoadString(pInfoData->treeconflict_nodekind == svn_node_dir ? IDS_TREECONFLICT_RESOLVE_KEEPLOCALDIR : IDS_TREECONFLICT_RESOLVE_KEEPLOCALFILE);
					break;
				}
				sConflictReason.Format(uReasonID, (LPCTSTR)sConflictAction);

				CTreeConflictEditorDlg dlg;
				dlg.SetConflictInfoText(sConflictReason);
				dlg.SetResolveTexts(sResolveTheirs, sResolveMine);
				dlg.SetPath(treeConflictPath);
				dlg.SetConflictSources(stat.status->tree_conflict->src_left_version, stat.status->tree_conflict->src_right_version);
				dlg.SetConflictReason(pInfoData->treeconflict_reason);
				dlg.SetConflictAction(pInfoData->treeconflict_action);
				INT_PTR dlgRet = dlg.DoModal();
				bRet = (dlgRet != IDCANCEL);
			}
		}
	}

	return bRet;
}
예제 #6
0
//////////////////////////////////////////////////////////////////////////
// IDataObject
//////////////////////////////////////////////////////////////////////////
STDMETHODIMP SVNDataObject::GetData(FORMATETC* pformatetcIn, STGMEDIUM* pmedium)
{
	if (pformatetcIn == NULL)
		return E_INVALIDARG;
	if (pmedium == NULL)
		return E_POINTER;
	pmedium->hGlobal = NULL;

	if ((pformatetcIn->tymed & TYMED_ISTREAM) && (pformatetcIn->dwAspect == DVASPECT_CONTENT) && (pformatetcIn->cfFormat == CF_FILECONTENTS))
	{
		// supports the IStream format.
		// The lindex param is the index of the file to return

		// Note: we don't get called for directories since those are simply created and don't
		// need to be fetched.

		// Note2: It would be really nice if we could get a stream from the subversion library
		// from where we could read the file contents. But the Subversion lib is not implemented
		// to *read* from a remote stream but so that the library *writes* to a stream we pass.
		// Since we can't get such a read stream, we have to fetch the file in whole first to
		// a temp location and then pass the shell an IStream for that temp file.
		CTSVNPath filepath;
		IStream * pIStream = NULL;
		if (m_revision.IsWorking())
		{
			if ((pformatetcIn->lindex >= 0)&&(pformatetcIn->lindex < (LONG)m_allPaths.size()))
			{
				filepath = m_allPaths[pformatetcIn->lindex].rootpath;
			}
		}
		else
		{
			filepath = CTempFiles::Instance().GetTempFilePath(true);
			if ((pformatetcIn->lindex >= 0)&&(pformatetcIn->lindex < (LONG)m_allPaths.size()))
			{
				if (!m_svn.Cat(CTSVNPath(m_allPaths[pformatetcIn->lindex].infodata.url), m_pegRev, m_revision, filepath))
				{
					DeleteFile(filepath.GetWinPath());
					return STG_E_ACCESSDENIED;
				}
			}
		}
		HRESULT res = SHCreateStreamOnFile(filepath.GetWinPath(), STGM_READ, &pIStream);
		if (res == S_OK)
		{
			pmedium->pstm = pIStream;
			pmedium->tymed = TYMED_ISTREAM;
			return S_OK;
		}
		return res;
	}
	else if ((pformatetcIn->tymed & TYMED_HGLOBAL) && (pformatetcIn->dwAspect == DVASPECT_CONTENT) && (pformatetcIn->cfFormat == CF_FILEDESCRIPTOR))
	{
		// now it is time to get all sub folders for the directories we have
		SVNInfo svnInfo;
		// find the common directory of all the paths
		CTSVNPath commonDir;
		bool bAllUrls = true;
		for (int i=0; i<m_svnPaths.GetCount(); ++i)
		{
			if (!m_svnPaths[i].IsUrl())
				bAllUrls = false;
			if (commonDir.IsEmpty())
				commonDir = m_svnPaths[i].GetContainingDirectory();
			if (!commonDir.IsEquivalentTo(m_svnPaths[i].GetContainingDirectory()))
			{
				commonDir.Reset();
				break;
			}
		}
		if (bAllUrls && (m_svnPaths.GetCount() > 1) && !commonDir.IsEmpty())
		{
			// if all paths are in the same directory, we can fetch the info recursively
			// from the parent folder to save a lot of time.
			const SVNInfoData * infodata = svnInfo.GetFirstFileInfo(commonDir, m_pegRev, m_revision, svn_depth_infinity);
			while (infodata)
			{
				// check if the returned item is one in our list
				for (int i=0; i<m_svnPaths.GetCount(); ++i)
				{
					if (m_svnPaths[i].IsAncestorOf(CTSVNPath(infodata->url)))
					{
						SVNDataObject::SVNObjectInfoData id = {m_svnPaths[i], *infodata};
						m_allPaths.push_back(id);
						break;
					}
				}
				infodata = svnInfo.GetNextFileInfo();
			}
		}
		else
		{
			for (int i = 0; i < m_svnPaths.GetCount(); ++i)
			{
				if (m_svnPaths[i].IsUrl())
				{
					const SVNInfoData * infodata = svnInfo.GetFirstFileInfo(m_svnPaths[i], m_pegRev, m_revision, svn_depth_infinity);
					while (infodata)
					{
						SVNDataObject::SVNObjectInfoData id = {m_svnPaths[i], *infodata};
						m_allPaths.push_back(id);
						infodata = svnInfo.GetNextFileInfo();
					}
				}
				else
				{
					SVNDataObject::SVNObjectInfoData id = {m_svnPaths[i], SVNInfoData()};
					m_allPaths.push_back(id);
				}
			}
		}
		size_t dataSize = sizeof(FILEGROUPDESCRIPTOR) + ((m_allPaths.size() - 1) * sizeof(FILEDESCRIPTOR));
		HGLOBAL data = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE | GMEM_ZEROINIT, dataSize);

		FILEGROUPDESCRIPTOR* files = (FILEGROUPDESCRIPTOR*)GlobalLock(data);
		files->cItems = static_cast<UINT>(m_allPaths.size());
		int index = 0;
		for (vector<SVNDataObject::SVNObjectInfoData>::const_iterator it = m_allPaths.begin(); it != m_allPaths.end(); ++it)
		{
			CString temp;
			if (it->rootpath.IsUrl())
			{
				temp = CUnicodeUtils::GetUnicode(CPathUtils::PathEscape(CUnicodeUtils::GetUTF8(it->rootpath.GetContainingDirectory().GetSVNPathString())));
				temp = it->infodata.url.Mid(temp.GetLength()+1);
				// we have to unescape the urls since the local file system doesn't need them
				// escaped and it would only look really ugly (and be wrong).
				temp = CPathUtils::PathUnescape(temp);
			}
			else
			{
				temp = it->rootpath.GetUIFileOrDirectoryName();
			}
			_tcscpy_s(files->fgd[index].cFileName, MAX_PATH, (LPCTSTR)temp);
			files->fgd[index].dwFlags = FD_ATTRIBUTES | FD_PROGRESSUI | FD_FILESIZE | FD_LINKUI;
			if (it->rootpath.IsUrl())
			{
				files->fgd[index].dwFileAttributes = (it->infodata.kind == svn_node_dir) ? FILE_ATTRIBUTE_DIRECTORY : FILE_ATTRIBUTE_NORMAL;
			}
			else
			{
				files->fgd[index].dwFileAttributes = it->rootpath.IsDirectory() ? FILE_ATTRIBUTE_DIRECTORY : FILE_ATTRIBUTE_NORMAL;
			}
			// Always set the file size to 0 even if we 'know' the file size (infodata.size64).
			// Because for text files, the file size is too low due to the EOLs getting converted
			// to CRLF (from LF as stored in the repository). And a too low file size set here
			// prevents the shell from reading the full file later - it only reads the stream up
			// to the number of bytes specified here. Which means we would end up with a truncated
			// text file (binary files are still ok though).
			files->fgd[index].nFileSizeLow = 0;
			files->fgd[index].nFileSizeHigh = 0;

			++index;
		}

		GlobalUnlock(data);

		pmedium->hGlobal = data;
		pmedium->tymed = TYMED_HGLOBAL;
		return S_OK;
	}
	// handling CF_PREFERREDDROPEFFECT is necessary to tell the shell that it should *not* ask for the
	// CF_FILEDESCRIPTOR until the drop actually occurs. If we don't handle CF_PREFERREDDROPEFFECT, the shell
	// will ask for the file descriptor for every object (file/folder) the mouse pointer hovers over and is
	// a potential drop target.
	else if ((pformatetcIn->tymed & TYMED_HGLOBAL) && (pformatetcIn->cfFormat == CF_PREFERREDDROPEFFECT))
	{
		HGLOBAL data = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE | GMEM_ZEROINIT, sizeof(DWORD));
		DWORD* effect = (DWORD*) GlobalLock(data);
		(*effect) = DROPEFFECT_COPY;
		GlobalUnlock(data);
		pmedium->hGlobal = data;
		pmedium->tymed = TYMED_HGLOBAL;
		return S_OK;
	}
	else if ((pformatetcIn->tymed & TYMED_HGLOBAL) && (pformatetcIn->dwAspect == DVASPECT_CONTENT) && (pformatetcIn->cfFormat == CF_TEXT))
	{
		// caller wants text
		// create the string from the path list
		CString text;
		if (m_svnPaths.GetCount())
		{
			// create a single string where the URLs are separated by newlines
			for (int i=0; i<m_svnPaths.GetCount(); ++i)
			{
				if (m_svnPaths[i].IsUrl())
					text += m_svnPaths[i].GetSVNPathString();
				else
					text += m_svnPaths[i].GetWinPathString();
				text += _T("\r\n");
			}
		}
		CStringA texta = CUnicodeUtils::GetUTF8(text);
		pmedium->tymed = TYMED_HGLOBAL;
		pmedium->hGlobal = GlobalAlloc(GHND, (texta.GetLength()+1)*sizeof(char));
		if (pmedium->hGlobal)
		{
			char* pMem = (char*)GlobalLock(pmedium->hGlobal);
			strcpy_s(pMem, texta.GetLength()+1, (LPCSTR)texta);
			GlobalUnlock(pmedium->hGlobal);
		}
		pmedium->pUnkForRelease = NULL;
		return S_OK;
	}
	else if ((pformatetcIn->tymed & TYMED_HGLOBAL) && (pformatetcIn->dwAspect == DVASPECT_CONTENT) && (pformatetcIn->cfFormat == CF_UNICODETEXT))
	{
		// caller wants Unicode text
		// create the string from the path list
		CString text;
		if (m_svnPaths.GetCount())
		{
			// create a single string where the URLs are separated by newlines
			for (int i=0; i<m_svnPaths.GetCount(); ++i)
			{
				if (m_svnPaths[i].IsUrl())
					text += m_svnPaths[i].GetSVNPathString();
				else
					text += m_svnPaths[i].GetWinPathString();
				text += _T("\r\n");
			}
		}
		pmedium->tymed = TYMED_HGLOBAL;
		pmedium->hGlobal = GlobalAlloc(GHND, (text.GetLength()+1)*sizeof(TCHAR));
		if (pmedium->hGlobal)
		{
			TCHAR* pMem = (TCHAR*)GlobalLock(pmedium->hGlobal);
			_tcscpy_s(pMem, text.GetLength()+1, (LPCTSTR)text);
			GlobalUnlock(pmedium->hGlobal);
		}
		pmedium->pUnkForRelease = NULL;
		return S_OK;
	}
	else if ((pformatetcIn->tymed & TYMED_HGLOBAL) && (pformatetcIn->dwAspect == DVASPECT_CONTENT) && (pformatetcIn->cfFormat == CF_SVNURL))
	{
		// caller wants the svn url
		// create the string from the path list
		CString text;
		if (m_svnPaths.GetCount())
		{
			// create a single string where the URLs are separated by newlines
			for (int i=0; i<m_svnPaths.GetCount(); ++i)
			{
				if (m_svnPaths[i].IsUrl())
				{
					text += m_svnPaths[i].GetSVNPathString();
					text += _T("?");
					text += m_revision.ToString();
				}
				else
					text += m_svnPaths[i].GetWinPathString();
				text += _T("\r\n");
			}
		}
		pmedium->tymed = TYMED_HGLOBAL;
		pmedium->hGlobal = GlobalAlloc(GHND, (text.GetLength()+1)*sizeof(TCHAR));
		if (pmedium->hGlobal)
		{
			TCHAR* pMem = (TCHAR*)GlobalLock(pmedium->hGlobal);
			_tcscpy_s(pMem, text.GetLength()+1, (LPCTSTR)text);
			GlobalUnlock(pmedium->hGlobal);
		}
		pmedium->pUnkForRelease = NULL;
		return S_OK;
	}
	else if ((pformatetcIn->tymed & TYMED_HGLOBAL) && (pformatetcIn->dwAspect == DVASPECT_CONTENT) && (pformatetcIn->cfFormat == CF_HDROP))
	{
		int nLength = 0;

		for (int i=0;i<m_svnPaths.GetCount();i++)
		{
			nLength += m_svnPaths[i].GetWinPathString().GetLength();
			nLength += 1; // '\0' separator
		}

		int nBufferSize = sizeof(DROPFILES) + (nLength+1)*sizeof(TCHAR);
		char * pBuffer = new char[nBufferSize];

		SecureZeroMemory(pBuffer, nBufferSize);

		DROPFILES* df = (DROPFILES*)pBuffer;
		df->pFiles = sizeof(DROPFILES);
		df->fWide = 1;

		TCHAR* pFilenames = (TCHAR*)(pBuffer + sizeof(DROPFILES));
		TCHAR* pCurrentFilename = pFilenames;

		for (int i=0;i<m_svnPaths.GetCount();i++)
		{
			CString str = m_svnPaths[i].GetWinPathString();
			wcscpy_s(pCurrentFilename, str.GetLength()+1, (LPCWSTR)str);
			pCurrentFilename += str.GetLength();
			*pCurrentFilename = '\0'; // separator between file names
			pCurrentFilename++;
		}
		*pCurrentFilename = '\0'; // terminate array

		pmedium->tymed = TYMED_HGLOBAL;
		pmedium->hGlobal = GlobalAlloc(GMEM_ZEROINIT|GMEM_MOVEABLE|GMEM_DDESHARE, nBufferSize);
		if (pmedium->hGlobal)
		{
			LPVOID pMem = ::GlobalLock(pmedium->hGlobal);
			if (pMem)
				memcpy(pMem, pBuffer, nBufferSize);
			GlobalUnlock(pmedium->hGlobal);
		}
		pmedium->pUnkForRelease = NULL;
		delete [] pBuffer;
		return S_OK;
	}

	for (size_t i=0; i<m_vecFormatEtc.size(); ++i)
	{
		if ((pformatetcIn->tymed == m_vecFormatEtc[i]->tymed) &&
			(pformatetcIn->dwAspect == m_vecFormatEtc[i]->dwAspect) &&
			(pformatetcIn->cfFormat == m_vecFormatEtc[i]->cfFormat))
		{
			CopyMedium(pmedium, m_vecStgMedium[i], m_vecFormatEtc[i]);
			return S_OK;
		}
	}

	return DV_E_FORMATETC;
}
bool ConflictEditorCommand::Execute()
{
    CTSVNPath merge = cmdLinePath;
    CTSVNPath directory = merge.GetDirectory();
    bool bRet = false;
    bool bAlternativeTool = !!parser.HasKey(L"alternative");

    // Use Subversion 1.10 API to resolve possible tree conlifcts.
    SVNConflictInfo conflict;
    if (!conflict.Get(merge))
    {
        conflict.ShowErrorDialog(GetExplorerHWND());
        return false;
    }

    // Resolve tree conflicts first.
    if (conflict.HasTreeConflict())
    {
        CProgressDlg progressDlg;
        progressDlg.SetTitle(IDS_PROC_EDIT_TREE_CONFLICTS);
        CString sProgressLine;
        sProgressLine.LoadString(IDS_PROGRS_FETCHING_TREE_CONFLICT_INFO);
        progressDlg.SetLine(1, sProgressLine);
        progressDlg.SetShowProgressBar(false);
        progressDlg.ShowModal(GetExplorerHWND(), FALSE);
        conflict.SetProgressDlg(&progressDlg);
        if (!conflict.FetchTreeDetails())
        {
            // Ignore errors while fetching additional tree conflict information.
            // Use still may want to resolve it manually.
            conflict.ClearSVNError();
        }
        progressDlg.Stop();
        conflict.SetProgressDlg(NULL);

        CNewTreeConflictEditorDlg dlg;
        dlg.SetConflictInfo(&conflict);

        dlg.DoModal(GetExplorerHWND());
        if (dlg.IsCancelled())
            return false;

        if (dlg.GetResult() == svn_client_conflict_option_postpone)
            return false;

        // Send notififcation that status may be changed. We cannot use
        // '/resolvemsghwnd' here because satus of multiple files may be changed
        // during tree conflict resolution.
        if (parser.HasVal(L"refreshmsghwnd"))
        {
            HWND refreshMsgWnd = (HWND)parser.GetLongLongVal(L"refreshmsghwnd");
            UINT WM_REFRESH_STATUS_MSG = RegisterWindowMessage(L"TORTOISESVN_REFRESH_STATUS_MSG");
            ::PostMessage(refreshMsgWnd, WM_REFRESH_STATUS_MSG, 0, 0);
        }
    }

    // we have the conflicted file (%merged)
    // now look for the other required files

    SVNInfo info;
    const SVNInfoData * pInfoData = info.GetFirstFileInfo(merge, SVNRev(), SVNRev());
    if (pInfoData == NULL)
        return false;

    for (auto conflIt = pInfoData->conflicts.cbegin(); conflIt != pInfoData->conflicts.cend(); ++conflIt)
    {
        switch (conflIt->kind)
        {
        case svn_wc_conflict_kind_text:
        {
            // we have a text conflict, use our merge tool to resolve the conflict

            CTSVNPath theirs = CTSVNPath(conflIt->conflict_new);
            CTSVNPath mine = CTSVNPath(conflIt->conflict_wrk);
            CTSVNPath base = CTSVNPath(conflIt->conflict_old);
            if (mine.IsEmpty())
                mine = merge;
            bRet = !!CAppUtils::StartExtMerge(CAppUtils::MergeFlags().AlternativeTool(bAlternativeTool),
                                              base, theirs, mine, merge, true, CString(), CString(), CString(), CString(), merge.GetFileOrDirectoryName());
        }
        break;
        case svn_wc_conflict_kind_property:
        {
            // we have a property conflict
            CTSVNPath prej(conflIt->prejfile);
            CEditPropConflictDlg dlg;
            dlg.SetPrejFile(prej);
            dlg.SetConflictedItem(merge);
            dlg.SetPropertyName(conflIt->propname);
            dlg.SetPropValues(conflIt->propvalue_base, conflIt->propvalue_working, conflIt->propvalue_incoming_old, conflIt->propvalue_incoming_new);
            bRet = (dlg.DoModal() != IDCANCEL);
        }
        break;
        case svn_wc_conflict_kind_tree:
        {
            CTSVNPath treeConflictPath = CTSVNPath(conflIt->treeconflict_path);

            CTreeConflictEditorDlg dlg;
            dlg.SetPath(treeConflictPath);
            dlg.SetConflictLeftSources(conflIt->src_left_version_url, conflIt->src_left_version_path, conflIt->src_left_version_rev, conflIt->src_left_version_kind);
            dlg.SetConflictRightSources(conflIt->src_right_version_url, conflIt->src_right_version_path, conflIt->src_right_version_rev, conflIt->src_right_version_kind);
            dlg.SetConflictReason(conflIt->treeconflict_reason);
            dlg.SetConflictAction(conflIt->treeconflict_action);
            dlg.SetConflictOperation(conflIt->treeconflict_operation);
            dlg.SetKind(conflIt->treeconflict_nodekind);
            INT_PTR dlgRet = dlg.DoModal();
            bRet = (dlgRet != IDCANCEL);
        }
        break;
        }
    }

    return bRet;
}
예제 #8
0
bool CFullHistory::FetchRevisionData ( CString path
                                     , SVNRev pegRev
                                     , bool showWCRev
                                     , bool showWCModification
                                     , CProgressDlg* progress
                                     , ITaskbarList3 * pTaskBarList
                                     , HWND hWnd)
{
    // clear any previously existing SVN error info

    svn_error_clear(Err);
    Err = NULL;

    // remove internal data from previous runs

    CFuture<bool> clearJob (this, &CFullHistory::ClearCopyInfo, &cpuLoadScheduler);

    // set some text on the progress dialog, before we wait
    // for the log operation to start
    this->progress = progress;
    this->taskbarlist = pTaskBarList;
    this->hwnd = hWnd;

    CString temp;
    temp.LoadString (IDS_REVGRAPH_PROGGETREVS);
    progress->SetLine(1, temp);

    temp.LoadString (IDS_REVGRAPH_PROGPREPARING);
    progress->SetLine(2, temp);
    progress->SetProgress(0, 1);
    progress->ShowModeless (hWnd);
    if (taskbarlist)
    {
        taskbarlist->SetProgressState(hwnd, TBPF_INDETERMINATE);
    }

    // prepare the path for Subversion
    CTSVNPath svnPath (path);
    CStringA url = CPathUtils::PathEscape
                        (CUnicodeUtils::GetUTF8
                            (svn.GetURLFromPath (svnPath)));

    // we have to get the log from the repository root

    CTSVNPath rootPath;
    svn_revnum_t head;
    if (FALSE == svn.GetRootAndHead (svnPath, rootPath, head))
    {
        Err = svn_error_dup(const_cast<svn_error_t*>(svn.GetSVNError()));
        return false;
    }

    if (pegRev.IsHead())
        pegRev = head;

    headRevision = head;
    CString escapedRepoRoot = rootPath.GetSVNPathString();
    relPath = CPathUtils::PathUnescape (url.Mid (escapedRepoRoot.GetLength()));
    repoRoot = CPathUtils::PathUnescape (escapedRepoRoot);

    // fix issue #360: use WC revision as peg revision

    pegRevision = pegRev;
    if (pegRevision == NO_REVISION)
    {
        if (!svnPath.IsUrl())
        {
            SVNInfo info;
            const SVNInfoData * baseInfo
                = info.GetFirstFileInfo (svnPath, SVNRev(), SVNRev());
            if (baseInfo != NULL)
                pegRevision = baseInfo->rev;
        }
    }

    // fetch missing data from the repository
    try
    {
        // select / construct query object and optimize revision range to fetch

        svnQuery.reset (new CSVNLogQuery (ctx, pool));

        bool cacheIsComplete = false;
        if (svn.GetLogCachePool()->IsEnabled())
        {
            CLogCachePool* pool = svn.GetLogCachePool();
            query.reset (new CCacheLogQuery (pool, svnQuery.get()));

            // get the cache and the lowest missing revision
            // (in off-line mode, the query may not find the cache as
            // it cannot contact the server to get the UUID)

            uuid = pool->GetRepositoryInfo().GetRepositoryUUID (rootPath);
            cache = pool->GetCache (uuid, escapedRepoRoot);

            firstRevision = cache != NULL
                          ? cache->GetRevisions().GetFirstMissingRevision(1)
                          : 0;

            // if the cache is already complete, the firstRevision here is
            // HEAD+1 - that revision does not exist and would throw an error later

            if (firstRevision > headRevision)
            {
                cacheIsComplete = true;
                firstRevision = headRevision;
            }
        }
        else
        {
            query.reset (new CCacheLogQuery (svn, svnQuery.get()));
            cache = NULL;
            firstRevision = 0;
        }

        // Find the revision the working copy is on, we mark that revision
        // later in the graph (handle option changes properly!).
        // For performance reasons, we only don't do it if we want to display it.

        wcInfo = SWCInfo (pegRev);
        if (showWCRev || showWCModification)
        {
            new CAsyncCall ( this
                           , &CFullHistory::QueryWCRevision
                           , true
                           , path
                           , &diskIOScheduler);

            new CAsyncCall ( this
                           , &CFullHistory::QueryWCRevision
                           , false
                           , path
                           , &diskIOScheduler);
        }

        // actually fetch the data

        if (!cacheIsComplete)
            query->Log ( CTSVNPathList (rootPath)
                       , headRevision
                       , headRevision
                       , firstRevision
                       , 0
                       , false      // strictNodeHistory
                       , this
                       , false      // includeChanges (log cache fetches them automatically)
                       , false      // includeMerges
                       , true       // includeStandardRevProps
                       , false      // includeUserRevProps
                       , TRevPropNames());

        // Store updated cache data

        if (cache == NULL)
        {
            cache = query->GetCache();

            // This should never happen:

            if (cache == NULL)
                return false;
        }
        else
        {
            if (cache->IsModified())
                new CAsyncCall ( cache
                               , &LogCache::CCachedLogInfo::Save
                               , &cpuLoadScheduler);
        }

        // store WC path

        const CPathDictionary* paths = &cache->GetLogInfo().GetPaths();
        wcPath.reset (new CDictionaryBasedTempPath (paths, (const char*)relPath));

        // wait for the cleanup jobs to finish before starting new ones
        // that depend of them

        clearJob.GetResult();

        // analyse the data

        new CAsyncCall ( this
                       , &CFullHistory::AnalyzeRevisionData
                       , &cpuLoadScheduler);

        // pre-process log data (invert copy-relationship)

        new CAsyncCall ( this
                       , &CFullHistory::BuildForwardCopies
                       , &cpuLoadScheduler);

        // Wait for the jobs to finish

        if (showWCRev || showWCModification)
        {
            temp.LoadString (IDS_REVGRAPH_PROGREADINGWC);
            progress->SetLine(2, temp);
        }

        cpuLoadScheduler.WaitForEmptyQueue();
        diskIOScheduler.WaitForEmptyQueue();
    }
    catch (SVNError& e)
    {
        Err = svn_error_create (e.GetCode(), NULL, e.GetMessage());
        return false;
    }

    return true;
}