/** * @brief Draws rect indicating visible area in file views. * * @param [in] nTopLine New topline for indicator * @param [in] nBottomLine New bottomline for indicator * @todo This function dublicates too much DrawRect() code. */ void CLocationView::DrawVisibleAreaRect(CDC *pClientDC, int nTopLine, int nBottomLine) { CMergeDoc* pDoc = GetDocument(); if (nTopLine == -1) nTopLine = pDoc->GetRightView()->GetTopSubLine(); if (nBottomLine == -1) { const int nScreenLines = pDoc->GetRightView()->GetScreenLines(); nBottomLine = nTopLine + nScreenLines; } CRect rc; GetClientRect(rc); const int nbLines = min(m_view[MERGE_VIEW_LEFT]->GetSubLineCount(), m_view[MERGE_VIEW_RIGHT]->GetSubLineCount()); int nTopCoord = static_cast<int>(Y_OFFSET + (static_cast<double>(nTopLine * m_lineInPix))); int nBottomCoord = static_cast<int>(Y_OFFSET + (static_cast<double>(nBottomLine * m_lineInPix))); double xbarBottom = min(nbLines / m_pixInLines + Y_OFFSET, rc.Height() - Y_OFFSET); int barBottom = (int)xbarBottom; // Make sure bottom coord is in bar range nBottomCoord = min(nBottomCoord, barBottom); // Ensure visible area is at least minimum height if (nBottomCoord - nTopCoord < INDICATOR_MIN_HEIGHT) { // If area is near top of file, add additional area to bottom // of the bar and vice versa. if (nTopCoord < Y_OFFSET + 20) nBottomCoord += INDICATOR_MIN_HEIGHT - (nBottomCoord - nTopCoord); else { // Make sure locationbox has min hight if ((nBottomCoord - nTopCoord) < INDICATOR_MIN_HEIGHT) { // If we have a high number of lines, it may be better // to keep the topline, otherwise the cursor can // jump up and down unexpected nBottomCoord = nTopCoord + INDICATOR_MIN_HEIGHT; } } } // Store current values for later use (to check if area changes) m_visibleTop = nTopCoord; m_visibleBottom = nBottomCoord; CRect rcVisibleArea(2, m_visibleTop, rc.right - 2, m_visibleBottom); CBitmap *pBitmap = CopyRectToBitmap(pClientDC, rcVisibleArea); CBitmap *pDarkenedBitmap = GetDarkenedBitmap(pClientDC, pBitmap); DrawBitmap(pClientDC, rcVisibleArea.left, rcVisibleArea.top, pDarkenedBitmap); delete pDarkenedBitmap; delete pBitmap; }
/** * @brief Handle scroll events sent directly. * */ void CLocationView::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar *pScrollBar) { if (pScrollBar == NULL) { // Scroll did not come frome a scroll bar // Send it to the right view instead CMergeDoc *pDoc = GetDocument(); pDoc->GetRightView()->SendMessage(WM_VSCROLL, MAKELONG(nSBCode, nPos), (LPARAM)NULL); return; } CView::OnVScroll (nSBCode, nPos, pScrollBar); }
/** * @brief Update view. */ void CLocationView::OnUpdate( CView* pSender, LPARAM lHint, CObject* pHint ) { UNREFERENCED_PARAMETER(pSender); UNREFERENCED_PARAMETER(lHint); CMergeDoc* pDoc = GetDocument(); m_view[MERGE_VIEW_LEFT] = pDoc->GetLeftView(); m_view[MERGE_VIEW_RIGHT] = pDoc->GetRightView(); // Give pointer to MergeEditView m_view[MERGE_VIEW_LEFT]->SetLocationView(this); m_view[MERGE_VIEW_RIGHT]->SetLocationView(this); m_bRecalculateBlocks = TRUE; Invalidate(); }
/** * @brief Copy diff from right pane to left pane */ void CMergeDiffDetailView::OnR2l() { // Check that left side is not readonly if (IsReadOnly(0)) return; CMergeDoc *pDoc = GetDocument(); int currentDiff = pDoc->GetCurrentDiff(); if (currentDiff != -1 && pDoc->m_diffList.IsDiffSignificant(currentDiff)) { WaitStatusCursor waitstatus(IDS_STATUS_COPYR2L); pDoc->ListCopy(1, 0, currentDiff); } }
BOOL CMergeDiffDetailView::PreTranslateMessage(MSG* pMsg) { // Check if we got 'ESC pressed' -message if ((pMsg->message == WM_KEYDOWN) && (pMsg->wParam == VK_ESCAPE)) { // Ask about saving unsaved document, allow to cancel closing CMergeDoc *pd = GetDocument(); if (pd->PromptAndSaveIfNeeded(TRUE)) { AfxGetMainWnd()->PostMessage(WM_COMMAND, ID_FILE_CLOSE); return FALSE; } else return TRUE; } return CCrystalTextView::PreTranslateMessage(pMsg); }
/** * @brief Close MergeDocs opened from DirDoc. * * Asks confirmation for docs containing unsaved data and then * closes MergeDocs. * @return TRUE if success, FALSE if user canceled or closing failed */ BOOL CDirDoc::CloseMergeDocs() { POSITION pos = m_MergeDocs.GetHeadPosition(); while (pos) { CMergeDoc * pMergeDoc = m_MergeDocs.GetNext(pos); if (!pMergeDoc->CloseNow()) return FALSE; } pos = m_HexMergeDocs.GetHeadPosition(); while (pos) { CHexMergeDoc * pHexMergeDoc = m_HexMergeDocs.GetNext(pos); if (!pHexMergeDoc->CloseNow()) return FALSE; } return TRUE; }
/** * @brief Obtain a merge doc to display a difference in files. * @param [out] pNew Set to TRUE if a new doc is created, * and FALSE if an existing one reused. * @return Pointer to CMergeDoc to use (new or existing). */ CMergeDoc * CDirDoc::GetMergeDocForDiff(BOOL * pNew) { CMergeDoc * pMergeDoc = 0; // policy -- use an existing merge doc if available const BOOL bMultiDocs = GetOptionsMgr()->GetBool(OPT_MULTIDOC_MERGEDOCS); if (!bMultiDocs && !m_MergeDocs.IsEmpty()) { *pNew = FALSE; pMergeDoc = m_MergeDocs.GetHead(); } else { // Create a new merge doc pMergeDoc = (CMergeDoc*)theApp.m_pDiffTemplate->OpenDocumentFile(NULL); AddMergeDoc(pMergeDoc); pMergeDoc->SetDirDoc(this); *pNew = TRUE; } return pMergeDoc; }
/** * @brief Destructor. * * Clears document list and deleted possible archive-temp files. */ CDirDoc::~CDirDoc() { delete m_pCtxt; delete m_pCompareStats; // Inform all of our merge docs that we're closing POSITION pos = m_MergeDocs.GetHeadPosition(); while (pos) { CMergeDoc * pMergeDoc = m_MergeDocs.GetNext(pos); pMergeDoc->DirDocClosing(this); } pos = m_HexMergeDocs.GetHeadPosition(); while (pos) { CHexMergeDoc * pHexMergeDoc = m_HexMergeDocs.GetNext(pos); pHexMergeDoc->DirDocClosing(this); } // Delete all temporary folders belonging to this document while (m_pTempPathContext) { m_pTempPathContext = m_pTempPathContext->DeleteHead(); } }
/** * Show context menu and handle user selection. */ void CLocationView::OnContextMenu(CWnd* pWnd, CPoint point) { if (point.x == -1 && point.y == -1) { //keystroke invocation CRect rect; GetClientRect(rect); ClientToScreen(rect); point = rect.TopLeft(); point.Offset(5, 5); } CRect rc; CPoint pt = point; GetClientRect(rc); ScreenToClient(&pt); BCMenu menu; VERIFY(menu.LoadMenu(IDR_POPUP_LOCATIONBAR)); theApp.TranslateMenu(menu.m_hMenu); BCMenu* pPopup = (BCMenu *) menu.GetSubMenu(0); ASSERT(pPopup != NULL); CCmdUI cmdUI; cmdUI.m_pMenu = pPopup; cmdUI.m_nIndexMax = cmdUI.m_pMenu->GetMenuItemCount(); for (cmdUI.m_nIndex = 0 ; cmdUI.m_nIndex < cmdUI.m_nIndexMax ; ++cmdUI.m_nIndex) { cmdUI.m_nID = cmdUI.m_pMenu->GetMenuItemID(cmdUI.m_nIndex); switch (cmdUI.m_nID) { case ID_DISPLAY_MOVED_NONE: cmdUI.SetRadio(m_displayMovedBlocks == DISPLAY_MOVED_NONE); break; case ID_DISPLAY_MOVED_ALL: cmdUI.SetRadio(m_displayMovedBlocks == DISPLAY_MOVED_ALL); break; case ID_DISPLAY_MOVED_FOLLOW_DIFF: cmdUI.SetRadio(m_displayMovedBlocks == DISPLAY_MOVED_FOLLOW_DIFF); break; } } CString strItem; CString strNum; int nLine = -1; int bar = IsInsideBar(rc, pt); // If cursor over bar, format string with linenumber, else disable item if (bar != BAR_NONE) { // If outside bar area use left bar if (bar == BAR_YAREA) bar = BAR_LEFT; nLine = GetLineFromYPos(pt.y, bar); strNum.Format(_T("%d"), nLine + 1); // Show linenumber not lineindex } else pPopup->EnableMenuItem(ID_LOCBAR_GOTODIFF, MF_GRAYED); LangFormatString1(strItem, ID_LOCBAR_GOTOLINE_FMT, strNum); pPopup->SetMenuText(ID_LOCBAR_GOTODIFF, strItem, MF_BYCOMMAND); // invoke context menu // we don't want to use the main application handlers, so we use flags TPM_NONOTIFY | TPM_RETURNCMD // and handle the command after TrackPopupMenu int command = pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_NONOTIFY | TPM_RETURNCMD, point.x, point.y, AfxGetMainWnd()); CMergeDoc* pDoc = GetDocument(); switch (command) { case ID_LOCBAR_GOTODIFF: m_view[MERGE_VIEW_LEFT]->GotoLine(nLine, true, bar); if (bar == BAR_LEFT || bar == BAR_RIGHT) m_view[bar]->SetFocus(); break; case ID_EDIT_WMGOTO: m_view[MERGE_VIEW_LEFT]->WMGoto(); break; case ID_DISPLAY_MOVED_NONE: SetConnectMovedBlocks(DISPLAY_MOVED_NONE); pDoc->SetDetectMovedBlocks(FALSE); break; case ID_DISPLAY_MOVED_ALL: SetConnectMovedBlocks(DISPLAY_MOVED_ALL); pDoc->SetDetectMovedBlocks(TRUE); break; case ID_DISPLAY_MOVED_FOLLOW_DIFF: SetConnectMovedBlocks(DISPLAY_MOVED_FOLLOW_DIFF); pDoc->SetDetectMovedBlocks(TRUE); break; } }
/** * @brief Draw maps of files. * * Draws maps of differences in files. Difference list is walked and * every difference is drawn with same colors as in editview. * @note We MUST use doubles when calculating coords to avoid rounding * to integers. Rounding causes miscalculation of coords. * @sa CLocationView::DrawRect() */ void CLocationView::OnDraw(CDC* pDC) { ASSERT(m_view[MERGE_VIEW_LEFT] != NULL); ASSERT(m_view[MERGE_VIEW_RIGHT] != NULL); if (m_view[MERGE_VIEW_LEFT] == NULL || m_view[MERGE_VIEW_RIGHT] == NULL) return; if (!m_view[MERGE_VIEW_LEFT]->IsInitialized()) return; CRect rc; GetClientRect(&rc); CMemDC dc(pDC, &rc); COLORREF cr0 = CLR_NONE; // Left side color COLORREF cr1 = CLR_NONE; // Right side color COLORREF crt = CLR_NONE; // Text color BOOL bwh = FALSE; m_movedLines.RemoveAll(); CalculateBars(); DrawBackground(&dc); // Draw bar outlines CPen* oldObj = (CPen*)dc.SelectStockObject(BLACK_PEN); CBrush brush(m_view[0]->GetColor(COLORINDEX_WHITESPACE)); CBrush* oldBrush = (CBrush*)dc.SelectObject(&brush); dc.Rectangle(m_leftBar); dc.Rectangle(m_rightBar); dc.SelectObject(oldBrush); dc.SelectObject(oldObj); // Iterate the differences list and draw differences as colored blocks. // Don't recalculate blocks if we earlier determined it is not needed // This may save lots of processing if (m_bRecalculateBlocks) CalculateBlocks(); CMergeDoc *pDoc = GetDocument(); int nPrevEndY = -1; const int nCurDiff = pDoc->GetCurrentDiff(); vector<DiffBlock>::const_iterator iter = m_diffBlocks.begin(); while (iter != m_diffBlocks.end()) { CMergeEditView *pView = m_view[MERGE_VIEW_LEFT]; const BOOL bInsideDiff = (nCurDiff == (*iter).diff_index); if ((nPrevEndY != (*iter).bottom_coord) || bInsideDiff) { // Draw left side block m_view[MERGE_VIEW_LEFT]->GetLineColors2((*iter).top_line, 0, cr0, crt, bwh); CRect r0(m_leftBar.left, (*iter).top_coord, m_leftBar.right, (*iter).bottom_coord); DrawRect(&dc, r0, cr0, bInsideDiff); // Draw right side block m_view[MERGE_VIEW_RIGHT]->GetLineColors2((*iter).top_line, 0, cr1, crt, bwh); CRect r1(m_rightBar.left, (*iter).top_coord, m_rightBar.right, (*iter).bottom_coord); DrawRect(&dc, r1, cr1, bInsideDiff); } nPrevEndY = (*iter).bottom_coord; // Test if we draw a connector BOOL bDisplayConnectorFromLeft = FALSE; BOOL bDisplayConnectorFromRight = FALSE; switch (m_displayMovedBlocks) { case DISPLAY_MOVED_FOLLOW_DIFF: // display moved block only for current diff if (!bInsideDiff) break; // two sides may be linked to a block somewhere else bDisplayConnectorFromLeft = TRUE; bDisplayConnectorFromRight = TRUE; break; case DISPLAY_MOVED_ALL: // we display all moved blocks, so once direction is enough bDisplayConnectorFromLeft = TRUE; break; default: break; } if (bDisplayConnectorFromLeft) { int apparent0 = (*iter).top_line; int apparent1 = pDoc->RightLineInMovedBlock(apparent0); const int nBlockHeight = (*iter).bottom_line - (*iter).top_line; if (apparent1 != -1) { MovedLine line; CPoint start; CPoint end; apparent0 = pView->GetSubLineIndex(apparent0); apparent1 = pView->GetSubLineIndex(apparent1); start.x = m_leftBar.right; int leftUpper = (int) (apparent0 * m_lineInPix + Y_OFFSET); int leftLower = (int) ((nBlockHeight + apparent0) * m_lineInPix + Y_OFFSET); start.y = leftUpper + (leftLower - leftUpper) / 2; end.x = m_rightBar.left; int rightUpper = (int) (apparent1 * m_lineInPix + Y_OFFSET); int rightLower = (int) ((nBlockHeight + apparent1) * m_lineInPix + Y_OFFSET); end.y = rightUpper + (rightLower - rightUpper) / 2; line.ptLeft = start; line.ptRight = end; m_movedLines.AddTail(line); } } if (bDisplayConnectorFromRight) { int apparent1 = (*iter).top_line; int apparent0 = pDoc->LeftLineInMovedBlock(apparent1); const int nBlockHeight = (*iter).bottom_line - (*iter).top_line; if (apparent0 != -1) { MovedLine line; CPoint start; CPoint end; apparent0 = pView->GetSubLineIndex(apparent0); apparent1 = pView->GetSubLineIndex(apparent1); start.x = m_leftBar.right; int leftUpper = (int) (apparent0 * m_lineInPix + Y_OFFSET); int leftLower = (int) ((nBlockHeight + apparent0) * m_lineInPix + Y_OFFSET); start.y = leftUpper + (leftLower - leftUpper) / 2; end.x = m_rightBar.left; int rightUpper = (int) (apparent1 * m_lineInPix + Y_OFFSET); int rightLower = (int) ((nBlockHeight + apparent1) * m_lineInPix + Y_OFFSET); end.y = rightUpper + (rightLower - rightUpper) / 2; line.ptLeft = start; line.ptRight = end; m_movedLines.AddTail(line); } } ++iter; } if (m_displayMovedBlocks != DISPLAY_MOVED_NONE) DrawConnectLines(&dc); if (m_pSavedBackgroundBitmap) delete m_pSavedBackgroundBitmap; m_pSavedBackgroundBitmap = CopyRectToBitmap(&dc, rc); // Since we have invalidated locationbar there is no previous // arearect to remove m_visibleTop = -1; m_visibleBottom = -1; DrawVisibleAreaRect(&dc); m_bDrawn = true; }
void CMergeDiffDetailView::OnRefresh() { CMergeDoc *pd = GetDocument(); ASSERT(pd); pd->FlushAndRescan(TRUE); }