MENUITEM "Copy &from Left", ID_COPY_FROM_LEFT\r
MENUITEM "Copy fro&m Right", ID_COPY_FROM_RIGHT\r
MENUITEM SEPARATOR\r
+ MENUITEM "Copy Selected Line(s) to Right", ID_LINES_L2R\r
+ MENUITEM "Copy Selected Line(s) to Left", ID_LINES_R2L\r
+ MENUITEM "Copy Selected Line(s) from Left", ID_COPY_LINES_FROM_LEFT\r
+ MENUITEM "Copy Selected Line(s) from Right", ID_COPY_LINES_FROM_RIGHT\r
+ MENUITEM SEPARATOR\r
MENUITEM "&Select Line Difference\tF4", ID_SELECTLINEDIFF\r
MENUITEM "Add this change to Substitution &Filters", ID_ADD_TO_IGNORED_SUBSTITUTIONS\r
MENUITEM SEPARATOR\r
* @param [in] firstDiff First diff copied (0-based index)
* @param [in] lastDiff Last diff copied (0-based index)
*/
-void CMergeDoc::CopyMultipleList(int srcPane, int dstPane, int firstDiff, int lastDiff, int firstWordDiff, int lastWordDiff)
{
#ifdef _DEBUG
if (firstDiff > lastDiff)
FlushAndRescan();
}
+void CMergeDoc::CopyMultiplePartialList(int srcPane, int dstPane, int firstDiff, int lastDiff,
+ int firstLineDiff, int lastLineDiff)
+{
+ lastDiff = min(m_diffList.GetSize() - 1, lastDiff);
+ firstDiff = max(0, firstDiff);
+ if (firstDiff > lastDiff)
+ return;
+
+ RescanSuppress suppressRescan(*this);
+
+ bool bGroupWithPrevious = false;
+ if (firstLineDiff <= 0 && lastLineDiff == -1)
+ {
+ if (!ListCopy(srcPane, dstPane, -1, bGroupWithPrevious, true))
+ return; // sync failure
+ }
+ else
+ {
+ if (!PartialListCopy(srcPane, dstPane, lastDiff,
+ (firstDiff == lastDiff) ? firstLineDiff : 0, lastLineDiff, bGroupWithPrevious, true))
+ return; // sync failure
+ }
+
+
+ SetEditedAfterRescan(dstPane);
+
+ int nGroup = GetActiveMergeView()->m_nThisGroup;
+ CMergeEditView *pViewSrc = m_pView[nGroup][srcPane];
+ CMergeEditView *pViewDst = m_pView[nGroup][dstPane];
+ CPoint currentPosSrc = pViewSrc->GetCursorPos();
+ currentPosSrc.x = 0;
+ CPoint currentPosDst = pViewDst->GetCursorPos();
+ currentPosDst.x = 0;
+
+ CPoint pt(0, 0);
+ pViewDst->SetCursorPos(pt);
+ pViewDst->SetNewSelection(pt, pt, false);
+ pViewDst->SetNewAnchor(pt);
+
+ // copy from bottom up is more efficient
+ for (int i = lastDiff - 1; i >= firstDiff; --i)
+ {
+ if (m_diffList.IsDiffSignificant(i))
+ {
+ SetCurrentDiff(i);
+ const DIFFRANGE *pdi = m_diffList.DiffRangeAt(i);
+ if (currentPosDst.y > pdi->dend)
+ {
+ if (pdi->blank[dstPane] >= 0)
+ currentPosDst.y -= pdi->dend - pdi->blank[dstPane] + 1;
+ else if (pdi->blank[srcPane] >= 0)
+ currentPosDst.y -= pdi->dend - pdi->blank[srcPane] + 1;
+ }
+ // Group merge with previous (merge undo data to one action)
+ bGroupWithPrevious = true;
+ if (i > firstDiff || firstLineDiff <= 0)
+ {
+ if (!ListCopy(srcPane, dstPane, -1, bGroupWithPrevious, false))
+ break; // sync failure
+ }
+ else
+ {
+ if (!PartialListCopy(srcPane, dstPane, firstDiff, firstLineDiff, -1, bGroupWithPrevious, false))
+ break; // sync failure
+ }
+ }
+ }
+
+ ForEachView(dstPane, [currentPosDst](auto& pView) {
+ pView->SetCursorPos(currentPosDst);
+ pView->SetNewSelection(currentPosDst, currentPosDst, false);
+ pView->SetNewAnchor(currentPosDst);
+ });
+
+ suppressRescan.Clear(); // done suppress Rescan
+ FlushAndRescan();
+}
+
enum MergeResult { NoMergeNeeded, Merged, Conflict };
template<class Type>
return true;
}
+bool CMergeDoc::PartialListCopy(int srcPane, int dstPane, int nDiff, int firstLine, int lastLine /*= -1*/,
+ bool bGroupWithPrevious /*= false*/, bool bUpdateView /*= true*/)
+{
+ int nGroup = GetActiveMergeView()->m_nThisGroup;
+ CMergeEditView *pViewSrc = m_pView[nGroup][srcPane];
+ CMergeEditView *pViewDst = m_pView[nGroup][dstPane];
+ CCrystalTextView *pSource = bUpdateView ? pViewDst : nullptr;
+
+ // suppress Rescan during this method
+ // (Not only do we not want to rescan a lot of times, but
+ // it will wreck the line status array to rescan as we merge)
+ RescanSuppress suppressRescan(*this);
+
+ DIFFRANGE cd;
+ VERIFY(m_diffList.GetDiff(nDiff, cd));
+ CDiffTextBuffer& sbuf = *m_ptBuf[srcPane];
+ CDiffTextBuffer& dbuf = *m_ptBuf[dstPane];
+ bool bSrcWasMod = sbuf.IsModified();
+ const int cd_dbegin = (firstLine > cd.dbegin) ? firstLine : cd.dbegin;
+ const int cd_dend = cd.dend;
+ const int cd_blank = cd.blank[srcPane];
+ bool bInSync = SanityCheckDiff(cd);
+
+ if (!bInSync)
+ {
+ LangMessageBox(IDS_VIEWS_OUTOFSYNC, MB_ICONSTOP);
+ return false; // abort copying
+ }
+
+ // If we remove whole diff from current view, we must fix cursor
+ // position first. Normally we would move to end of previous line,
+ // but we want to move to begin of that line for usability.
+ if (bUpdateView)
+ {
+ CPoint currentPos = pViewDst->GetCursorPos();
+ currentPos.x = 0;
+ if (currentPos.y > cd_dend)
+ {
+ if (cd.blank[dstPane] >= 0)
+ currentPos.y -= cd_dend - cd.blank[dstPane] + 1;
+ else if (cd.blank[srcPane] >= 0)
+ currentPos.y -= cd_dend - cd.blank[srcPane] + 1;
+ }
+ ForEachView(dstPane, [currentPos](auto& pView) { pView->SetCursorPos(currentPos); });
+ }
+
+ // if the current diff contains missing lines, remove them from both sides
+ int limit = ((lastLine < 0) || (lastLine > cd_dend)) ? cd_dend : lastLine;
+
+ // curView is the view which is changed, so the opposite of the source view
+ dbuf.BeginUndoGroup(bGroupWithPrevious);
+ if ((cd_blank >= 0) && (cd_dbegin >= cd_blank))
+ {
+ // text was missing, so delete rest of lines on both sides
+ // delete only on destination side since rescan will clear the other side
+ if (limit+1 < dbuf.GetLineCount())
+ {
+ dbuf.DeleteText(pSource, cd_dbegin, 0, limit+1, 0, CE_ACTION_MERGE);
+ }
+ else
+ {
+ // To removing EOL chars of last line, deletes from the end of the line (cd_blank - 1).
+ ASSERT(cd_dbegin > 0);
+ dbuf.DeleteText(pSource, cd_dbegin-1, dbuf.GetLineLength(cd_dbegin-1), limit, dbuf.GetLineLength(limit), CE_ACTION_MERGE);
+ }
+
+ limit = cd_dbegin-1;
+ dbuf.FlushUndoGroup(pSource);
+ dbuf.BeginUndoGroup(true);
+ }
+
+ // copy the selected text over
+ if (cd_dbegin <= limit)
+ {
+ // text exists on left side, so just replace
+ dbuf.ReplaceFullLines(dbuf, sbuf, pSource, cd_dbegin, limit, CE_ACTION_MERGE);
+ dbuf.FlushUndoGroup(pSource);
+ dbuf.BeginUndoGroup(true);
+ }
+ dbuf.FlushUndoGroup(pSource);
+
+ // remove the diff
+ SetCurrentDiff(-1);
+
+ // reset the mod status of the source view because we do make some
+ // changes, but none that concern the source text
+ sbuf.SetModified(bSrcWasMod);
+
+ suppressRescan.Clear(); // done suppress Rescan
+ FlushAndRescan();
+ return true;
+}
+
bool CMergeDoc::WordListCopy(int srcPane, int dstPane, int nDiff, int firstWordDiff, int lastWordDiff,
const std::vector<int> *pWordDiffIndice, bool bGroupWithPrevious /*= false*/, bool bUpdateView /*= true*/)
{
bool Undo();
void CopyAllList(int srcPane, int dstPane);
void CopyMultipleList(int srcPane, int dstPane, int firstDiff, int lastDiff, int firstWordDiff = -1, int lastWordDiff = -1);
+ void CopyMultiplePartialList(int srcPane, int dstPane, int firstDiff, int lastDiff, int firstLineDiff = -1, int lastLineDiff = -1);
void DoAutoMerge(int dstPane);
bool SanityCheckDiff(DIFFRANGE dr) const;
bool WordListCopy(int srcPane, int dstPane, int nDiff, int nFirstWordDiff, int nLastWordDiff, const std::vector<int> *pWordDiffIndice, bool bGroupWithPrevious = false, bool bUpdateView = true);
+ bool PartialListCopy(int srcPane, int dstPane, int nDiff, int firstLine, int lastLine = -1, bool bGroupWithPrevious = false, bool bUpdateView = true);
bool ListCopy(int srcPane, int dstPane, int nDiff = -1, bool bGroupWithPrevious = false, bool bUpdateView = true);
bool TrySaveAs(String& strPath, int &nLastErrorCode, String & sError,
int nBuffer, PackingInfo * pInfoTempUnpacker);
ON_UPDATE_COMMAND_UI(ID_AUTO_MERGE, OnUpdateAutoMerge)
ON_COMMAND(ID_L2R, OnL2r)
ON_UPDATE_COMMAND_UI(ID_L2R, OnUpdateL2r)
+ ON_COMMAND(ID_LINES_L2R, OnLinesL2r)
+ ON_UPDATE_COMMAND_UI(ID_LINES_L2R, OnUpdateLinesL2r)
ON_COMMAND(ID_R2L, OnR2l)
ON_UPDATE_COMMAND_UI(ID_R2L, OnUpdateR2l)
+ ON_COMMAND(ID_LINES_R2L, OnLinesR2l)
+ ON_UPDATE_COMMAND_UI(ID_LINES_R2L, OnUpdateLinesR2l)
ON_COMMAND(ID_COPY_FROM_LEFT, OnCopyFromLeft)
ON_UPDATE_COMMAND_UI(ID_COPY_FROM_LEFT, OnUpdateCopyFromLeft)
+ ON_COMMAND(ID_COPY_LINES_FROM_LEFT, OnCopyLinesFromLeft)
+ ON_UPDATE_COMMAND_UI(ID_COPY_LINES_FROM_LEFT, OnUpdateCopyLinesFromLeft)
ON_COMMAND(ID_COPY_FROM_RIGHT, OnCopyFromRight)
ON_UPDATE_COMMAND_UI(ID_COPY_FROM_RIGHT, OnUpdateCopyFromRight)
+ ON_COMMAND(ID_COPY_LINES_FROM_RIGHT, OnCopyLinesFromRight)
+ ON_UPDATE_COMMAND_UI(ID_COPY_LINES_FROM_RIGHT, OnUpdateCopyLinesFromRight)
ON_COMMAND(ID_ADD_SYNCPOINT, OnAddSyncPoint)
ON_COMMAND(ID_CLEAR_SYNCPOINTS, OnClearSyncPoints)
ON_UPDATE_COMMAND_UI(ID_CLEAR_SYNCPOINTS, OnUpdateClearSyncPoints)
ASSERT(firstDiff != -1 ? firstWordDiff != -1 : true);
}
+void CMergeEditView::GetSelectedDiffs(int & firstDiff, int & lastDiff)
+{
+ firstDiff = -1;
+ lastDiff = -1;
+
+ CMergeDoc *pd = GetDocument();
+ const int nDiffs = pd->m_diffList.GetSignificantDiffs();
+ if (nDiffs == 0)
+ return;
+
+ int firstLine, lastLine;
+ CPoint ptStart, ptEnd;
+ GetSelection(ptStart, ptEnd);
+ firstLine = ptStart.y;
+ lastLine = ptEnd.y;
+
+ firstDiff = pd->m_diffList.LineToDiff(firstLine);
+ if (firstDiff == -1)
+ {
+ firstDiff = pd->m_diffList.NextSignificantDiffFromLine(firstLine);
+ if (firstDiff == -1)
+ return;
+ }
+ lastDiff = pd->m_diffList.LineToDiff(lastLine);
+ if (lastDiff == -1)
+ lastDiff = pd->m_diffList.PrevSignificantDiffFromLine(lastLine);
+ if (lastDiff < firstDiff)
+ {
+ firstDiff = -1;
+ return;
+ }
+
+ ASSERT(firstDiff == -1 ? (lastDiff == -1) : true);
+ ASSERT(lastDiff == -1 ? (firstDiff == -1) : true);
+}
+
std::map<int, std::vector<int>> CMergeEditView::GetColumnSelectedWordDiffIndice()
{
CMergeDoc *pDoc = GetDocument();
DeselectDiffIfCursorNotInCurrentDiff();
}
-void CMergeEditView::OnX2Y(int srcPane, int dstPane)
+void CMergeEditView::OnX2Y(int srcPane, int dstPane, bool selectedLineOnly)
{
// Check that right side is not readonly
if (IsReadOnly(dstPane))
{
if (!m_bRectangularSelection)
{
- int firstDiff, lastDiff, firstWordDiff, lastWordDiff;
- GetFullySelectedDiffs(firstDiff, lastDiff, firstWordDiff, lastWordDiff);
- if (firstDiff != -1 && lastDiff != -1)
+ if (selectedLineOnly)
{
- CWaitCursor waitstatus;
-
- // Setting CopyFullLine (OPT_COPY_FULL_LINE)
- // restore old copy behaviour (always copy "full line" instead of "selected text only"), with a hidden option
- if (GetOptionsMgr()->GetBool(OPT_COPY_FULL_LINE))
+ int firstDiff, lastDiff;
+ GetSelectedDiffs(firstDiff, lastDiff);
+ if (firstDiff != -1 && lastDiff != -1)
{
- // old behaviour: copy full line
- pDoc->CopyMultipleList(srcPane, dstPane, firstDiff, lastDiff);
+ CWaitCursor waitstatus;
+ pDoc->CopyMultiplePartialList(srcPane, dstPane, firstDiff, lastDiff, ptStart.y, ptEnd.y);
}
- else
+ }
+ else
+ {
+ int firstDiff, lastDiff, firstWordDiff, lastWordDiff;
+ GetFullySelectedDiffs(firstDiff, lastDiff, firstWordDiff, lastWordDiff);
+ if (firstDiff != -1 && lastDiff != -1)
{
- // new behaviour: copy selected text only
- pDoc->CopyMultipleList(srcPane, dstPane, firstDiff, lastDiff, firstWordDiff, lastWordDiff);
+ CWaitCursor waitstatus;
+
+ // Setting CopyFullLine (OPT_COPY_FULL_LINE)
+ // restore old copy behaviour (always copy "full line" instead of "selected text only"), with a hidden option
+ if (GetOptionsMgr()->GetBool(OPT_COPY_FULL_LINE))
+ {
+ // old behaviour: copy full line
+ pDoc->CopyMultipleList(srcPane, dstPane, firstDiff, lastDiff);
+ }
+ else
+ {
+ // new behaviour: copy selected text only
+ pDoc->CopyMultipleList(srcPane, dstPane, firstDiff, lastDiff, firstWordDiff, lastWordDiff);
+ }
}
}
}
}
else if (currentDiff != -1 && pDoc->m_diffList.IsDiffSignificant(currentDiff))
{
- CWaitCursor waitstatus;
- pDoc->ListCopy(srcPane, dstPane, currentDiff);
+ if (selectedLineOnly)
+ {
+ CWaitCursor waitstatus;
+ pDoc->PartialListCopy(srcPane, dstPane, currentDiff, ptStart.y, ptEnd.y);
+ }
+ else
+ {
+ CWaitCursor waitstatus;
+ pDoc->ListCopy(srcPane, dstPane, currentDiff);
+ }
}
}
OnUpdateX2Y(m_nThisPane < GetDocument()->m_nBuffers - 1 ? m_nThisPane + 1 : GetDocument()->m_nBuffers - 1, pCmdUI);
}
+void CMergeEditView::OnLinesL2r()
+{
+ int dstPane = (m_nThisPane < GetDocument()->m_nBuffers - 1) ? m_nThisPane + 1 : GetDocument()->m_nBuffers - 1;
+ int srcPane = dstPane - 1;
+ OnX2Y(srcPane, dstPane, true);
+}
+
+void CMergeEditView::OnUpdateLinesL2r(CCmdUI* pCmdUI)
+{
+ OnUpdateX2Y(m_nThisPane < GetDocument()->m_nBuffers - 1 ? m_nThisPane + 1 : GetDocument()->m_nBuffers - 1, pCmdUI);
+}
+
/**
* @brief Copy diff from right pane to left pane
*
OnUpdateX2Y(m_nThisPane > 0 ? m_nThisPane - 1 : 0, pCmdUI);
}
+void CMergeEditView::OnLinesR2l()
+{
+ int dstPane = (m_nThisPane > 0) ? m_nThisPane - 1 : 0;
+ int srcPane = dstPane + 1;
+ OnX2Y(srcPane, dstPane, true);
+}
+
+void CMergeEditView::OnUpdateLinesR2l(CCmdUI* pCmdUI)
+{
+ OnUpdateX2Y(m_nThisPane > 0 ? m_nThisPane - 1 : 0, pCmdUI);
+}
+
void CMergeEditView::OnCopyFromLeft()
{
int dstPane = m_nThisPane;
OnUpdateX2Y(dstPane, pCmdUI);
}
+void CMergeEditView::OnCopyLinesFromLeft()
+{
+ int dstPane = m_nThisPane;
+ int srcPane = dstPane - 1;
+ if (srcPane < 0)
+ return;
+ OnX2Y(srcPane, dstPane, true);
+}
+
+void CMergeEditView::OnUpdateCopyLinesFromLeft(CCmdUI* pCmdUI)
+{
+ int dstPane = m_nThisPane;
+ int srcPane = dstPane - 1;
+ if (srcPane < 0)
+ pCmdUI->Enable(false);
+ else
+ OnUpdateX2Y(dstPane, pCmdUI);
+}
+
void CMergeEditView::OnCopyFromRight()
{
int dstPane = m_nThisPane;
OnUpdateX2Y(dstPane, pCmdUI);
}
+void CMergeEditView::OnCopyLinesFromRight()
+{
+ int dstPane = m_nThisPane;
+ int srcPane = dstPane + 1;
+ if (srcPane >= GetDocument()->m_nBuffers)
+ return;
+ OnX2Y(srcPane, dstPane, true);
+}
+
+void CMergeEditView::OnUpdateCopyLinesFromRight(CCmdUI* pCmdUI)
+{
+ int dstPane = m_nThisPane;
+ int srcPane = dstPane + 1;
+ if (srcPane >= GetDocument()->m_nBuffers)
+ pCmdUI->Enable(false);
+ else
+ OnUpdateX2Y(dstPane, pCmdUI);
+}
+
/**
* @brief Copy all diffs from right pane to left pane
*/
{
menu.RemoveMenu(ID_COPY_FROM_RIGHT, MF_BYCOMMAND);
menu.RemoveMenu(ID_COPY_FROM_LEFT, MF_BYCOMMAND);
+ menu.RemoveMenu(ID_COPY_LINES_FROM_RIGHT, MF_BYCOMMAND);
+ menu.RemoveMenu(ID_COPY_LINES_FROM_LEFT, MF_BYCOMMAND);
}
if (m_nThisPane == GetDocument()->m_nBuffers - 1)
{
menu.RemoveMenu(ID_COPY_FROM_LEFT, MF_BYCOMMAND);
menu.RemoveMenu(ID_COPY_FROM_RIGHT, MF_BYCOMMAND);
+ menu.RemoveMenu(ID_COPY_LINES_FROM_RIGHT, MF_BYCOMMAND);
+ menu.RemoveMenu(ID_COPY_LINES_FROM_LEFT, MF_BYCOMMAND);
}
// Remove "Go to Moved Line Between Middle and Right" if in 2-way file comparison.
const CCrystalTextBuffer *LocateTextBuffer () const { return const_cast<CMergeEditView *>(this)->LocateTextBuffer(); };
void GetFullySelectedDiffs(int & firstDiff, int & lastDiff);
void GetFullySelectedDiffs(int & firstDiff, int & lastDiff, int & firstWordDiff, int & lastWordDiff, const CPoint *pptStart = nullptr, const CPoint *ppEnd = nullptr);
+ void GetSelectedDiffs(int & firstDiff, int & lastDiff);
std::map<int, std::vector<int>> GetColumnSelectedWordDiffIndice();
CString GetSelectedText();
CString GetLineText(int idx);
afx_msg void OnUpdateAllRight(CCmdUI* pCmdUI);
afx_msg void OnAutoMerge();
afx_msg void OnUpdateAutoMerge(CCmdUI* pCmdUI);
- afx_msg void OnX2Y(int srcPane, int dstPane);
+ afx_msg void OnX2Y(int srcPane, int dstPane, bool selectedLineOnly = false);
afx_msg void OnUpdateX2Y(int dstPane, CCmdUI* pCmdUI);
afx_msg void OnL2r();
afx_msg void OnUpdateL2r(CCmdUI* pCmdUI);
+ afx_msg void OnLinesL2r();
+ afx_msg void OnUpdateLinesL2r(CCmdUI* pCmdUI);
afx_msg void OnR2l();
afx_msg void OnUpdateR2l(CCmdUI* pCmdUI);
+ afx_msg void OnLinesR2l();
+ afx_msg void OnUpdateLinesR2l(CCmdUI* pCmdUI);
afx_msg void OnCopyFromLeft();
afx_msg void OnUpdateCopyFromLeft(CCmdUI* pCmdUI);
+ afx_msg void OnCopyLinesFromLeft();
+ afx_msg void OnUpdateCopyLinesFromLeft(CCmdUI* pCmdUI);
afx_msg void OnCopyFromRight();
afx_msg void OnUpdateCopyFromRight(CCmdUI* pCmdUI);
+ afx_msg void OnCopyLinesFromRight();
+ afx_msg void OnUpdateCopyLinesFromRight(CCmdUI* pCmdUI);
afx_msg void OnAddSyncPoint();
afx_msg void OnClearSyncPoints();
afx_msg void OnUpdateClearSyncPoints(CCmdUI* pCmdUI);
#define IDS_OCRRESULT_TEXTONLY 34186\r
#define IDS_OCRRESULT_POS_LINE 34187\r
#define IDS_OCRRESULT_POS_WORD 34188\r
+#define ID_LINES_R2L 34190\r
+#define ID_LINES_L2R 34191\r
+#define ID_COPY_LINES_FROM_LEFT 34192\r
+#define ID_COPY_LINES_FROM_RIGHT 34193\r
\r
// Next default values for new objects\r
// \r