OSDN Git Service

PATCH [ 922724 ] "Don't display again" option for messageboxes
[winmerge-jp/winmerge-jp.git] / Src / DirActions.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 //    see Merge.cpp for license (GPLv2+) statement
3 //
4 /////////////////////////////////////////////////////////////////////////////
5 /**
6  *  @file DirActions.cpp
7  *
8  *  @brief Implementation of methods of CDirView that copy/move/delete files
9  */
10 // RCS ID line follows -- this is updated by CVS
11 // $Id$
12
13 // It would be nice to make this independent of the UI (CDirView)
14 // but it needs access to the list of selected items.
15 // One idea would be to provide an iterator over them.
16 //
17
18 #include "stdafx.h"
19 #include "Merge.h"
20 #include "DirView.h"
21 #include "DirDoc.h"
22 #include "MainFrm.h"
23 #include "coretools.h"
24 #include "OutputDlg.h"
25 #include "paths.h"
26 #include "CShellFileOp.h"
27 #include "OptionsDef.h"
28
29 #ifdef _DEBUG
30 #define new DEBUG_NEW
31 #undef THIS_FILE
32 static char THIS_FILE[] = __FILE__;
33 #endif
34
35 extern CLogFile gLog;
36
37 // Prompt user to confirm a multiple item copy
38 static BOOL ConfirmMultipleCopy(int count, int total)
39 {
40         CString s;
41         ASSERT(count>1);
42         AfxFormatString2(s, IDS_CONFIRM_COPY2DIR, NumToStr(count), NumToStr(total));
43         int rtn = AfxMessageBox(s, MB_YESNO|MB_ICONQUESTION|MB_DONT_ASK_AGAIN, IDS_CONFIRM_COPY2DIR);
44         return (rtn==IDYES);
45 }
46
47 // Prompt user to confirm a single item copy
48 static BOOL ConfirmSingleCopy(LPCTSTR src, LPCTSTR dest)
49 {
50         CString s;
51         AfxFormatString2(s, IDS_CONFIRM_COPY_SINGLE, src, dest);
52         int rtn = AfxMessageBox(s, MB_YESNO|MB_ICONQUESTION|MB_DONT_ASK_AGAIN, IDS_CONFIRM_COPY_SINGLE);
53         return (rtn==IDYES);
54 }
55
56 // Prompt user to confirm a multiple item delete
57 static BOOL ConfirmMultipleDelete(int count, int total)
58 {
59         CString s;
60         AfxFormatString2(s, IDS_CONFIRM_DELETE_ITEMS, NumToStr(count), NumToStr(total));
61         int rtn = AfxMessageBox(s, MB_YESNO|MB_ICONQUESTION|MB_DONT_ASK_AGAIN, IDS_CONFIRM_DELETE_ITEMS);
62         return (rtn==IDYES);
63 }
64
65 // Prompt user to confirm a single item delete
66 static BOOL ConfirmSingleDelete(LPCTSTR filepath)
67 {
68         CString s;
69         AfxFormatString1(s, IDS_CONFIRM_DELETE_SINGLE, filepath);
70         int rtn = AfxMessageBox(s, MB_YESNO|MB_ICONQUESTION|MB_DONT_ASK_AGAIN, IDS_CONFIRM_DELETE_SINGLE);
71         return (rtn==IDYES);
72 }
73
74 // Prompt & copy item from right to left, if legal
75 void CDirView::DoCopyRightToLeft()
76 {
77         // First we build a list of desired actions
78         ActionList actionList(ACT_COPY);
79         int sel=-1;
80         CString slFile, srFile;
81         while ((sel = m_pList->GetNextItem(sel, LVNI_SELECTED)) != -1)
82         {
83                 const DIFFITEM& di = GetDiffItem(sel);
84                 if (IsItemCopyableToLeft(di))
85                 {
86                         GetItemFileNames(sel, slFile, srFile);
87                         action act;
88                         act.src = srFile;
89                         act.dest = slFile;
90                         act.idx = sel;
91                         act.code = di.diffcode;
92                         act.dirflag = di.isDirectory();
93                         actionList.actions.AddTail(act);
94                 }
95                 ++actionList.selcount;
96         }
97
98         // Now we prompt, and execute actions
99         ConfirmAndPerformActions(actionList);
100 }
101 // Prompt & copy item from left to right, if legal
102 void CDirView::DoCopyLeftToRight()
103 {
104         // First we build a list of desired actions
105         ActionList actionList(ACT_COPY);
106         int sel=-1;
107         CString slFile, srFile;
108         while ((sel = m_pList->GetNextItem(sel, LVNI_SELECTED)) != -1)
109         {
110                 const DIFFITEM& di = GetDiffItem(sel);
111                 if (IsItemCopyableToRight(di))
112                 {
113                         GetItemFileNames(sel, slFile, srFile);
114                         action act;
115                         act.src = slFile;
116                         act.dest = srFile;
117                         act.dirflag = di.isDirectory();
118                         act.idx = sel;
119                         act.code = di.diffcode;
120                         actionList.actions.AddTail(act);
121                 }
122                 ++actionList.selcount;
123         }
124
125         // Now we prompt, and execute actions
126         ConfirmAndPerformActions(actionList);
127 }
128
129 // Prompt & delete left, if legal
130 void CDirView::DoDelLeft()
131 {
132         // First we build a list of desired actions
133         ActionList actionList(ACT_DEL_LEFT);
134         int sel=-1;
135         CString slFile, srFile;
136         while ((sel = m_pList->GetNextItem(sel, LVNI_SELECTED)) != -1)
137         {
138                 const DIFFITEM& di = GetDiffItem(sel);
139                 if (IsItemDeletableOnLeft(di))
140                 {
141                         GetItemFileNames(sel, slFile, srFile);
142                         action act;
143                         act.src = slFile;
144                         act.dirflag = di.isDirectory();
145                         act.idx = sel;
146                         act.code = di.diffcode;
147                         actionList.actions.AddTail(act);
148                 }
149                 ++actionList.selcount;
150         }
151
152         // Now we prompt, and execute actions
153         ConfirmAndPerformActions(actionList);
154 }
155 // Prompt & delete right, if legal
156 void CDirView::DoDelRight()
157 {
158         // First we build a list of desired actions
159         ActionList actionList(ACT_DEL_RIGHT);
160         int sel=-1;
161         CString slFile, srFile;
162         while ((sel = m_pList->GetNextItem(sel, LVNI_SELECTED)) != -1)
163         {
164                 const DIFFITEM& di = GetDiffItem(sel);
165
166                 if (IsItemDeletableOnRight(di))
167                 {
168                         GetItemFileNames(sel, slFile, srFile);
169                         action act;
170                         act.src = srFile;
171                         act.dirflag = di.isDirectory();
172                         act.idx = sel;
173                         act.code = di.diffcode;
174                         actionList.actions.AddTail(act);
175                 }
176                 ++actionList.selcount;
177         }
178
179         // Now we prompt, and execute actions
180         ConfirmAndPerformActions(actionList);
181 }
182 // Prompt & delete both, if legal
183 void CDirView::DoDelBoth()
184 {
185         // First we build a list of desired actions
186         ActionList actionList(ACT_DEL_BOTH);
187         int sel=-1;
188         CString slFile, srFile;
189         while ((sel = m_pList->GetNextItem(sel, LVNI_SELECTED)) != -1)
190         {
191                 const DIFFITEM& di = GetDiffItem(sel);
192
193                 if (IsItemDeletableOnBoth(di))
194                 {
195                         GetItemFileNames(sel, slFile, srFile);
196                         action act;
197                         act.src = srFile;
198                         act.dest = slFile;
199                         act.dirflag = di.isDirectory();
200                         act.idx = sel;
201                         act.code = di.diffcode;
202                         actionList.actions.AddTail(act);
203                 }
204                 ++actionList.selcount;
205         }
206
207         // Now we prompt, and execute actions
208         ConfirmAndPerformActions(actionList);
209 }
210
211 /**
212  * @brief Copy selected left-side files to user-specified directory
213  * @note CShellFileOp takes care of much of error handling
214  */
215 void CDirView::DoCopyLeftTo()
216 {
217         CShellFileOp fileOp;
218         CString destPath;
219         CString startPath;
220         CString msg;
221
222         VERIFY(msg.LoadString(IDS_SELECT_DESTFOLDER));
223         if (!SelectFolder(destPath, startPath, msg))
224                 return;
225
226         fileOp.SetOperationFlags(FO_COPY, this, FOF_NOCONFIRMMKDIR);
227         fileOp.AddDestFile(destPath);
228
229         int sel = -1;
230         CString slFile, srFile;
231         while ((sel = m_pList->GetNextItem(sel, LVNI_SELECTED)) != -1)
232         {
233                 const DIFFITEM& di = GetDiffItem(sel);
234
235                 if (IsItemCopyableToOnLeft(di))
236                 {
237                         GetItemFileNames(sel, slFile, srFile);
238                         fileOp.AddSourceFile(slFile);
239                 }
240         }
241
242         BOOL bSuccess = FALSE;
243         BOOL bAPICalled = FALSE;
244         BOOL bAborted = FALSE;
245         int  nAPIReturn = 0;
246         bSuccess = fileOp.Go(&bAPICalled, &nAPIReturn, &bAborted);
247 }
248
249 /**
250  * @brief Copy selected righ-side files to user-specified directory
251  * @note CShellFileOp takes care of much of error handling
252  */
253 void CDirView::DoCopyRightTo()
254 {
255         CShellFileOp fileOp;
256         CString destPath;
257         CString startPath;
258         CString msg;
259
260         VERIFY(msg.LoadString(IDS_SELECT_DESTFOLDER));
261         if (!SelectFolder(destPath, startPath, msg))
262                 return;
263
264         fileOp.SetOperationFlags(FO_COPY, this, FOF_NOCONFIRMMKDIR);
265         fileOp.AddDestFile(destPath);
266
267         int sel = -1;
268         CString slFile, srFile;
269         while ((sel = m_pList->GetNextItem(sel, LVNI_SELECTED)) != -1)
270         {
271                 const DIFFITEM& di = GetDiffItem(sel);
272
273                 if (IsItemCopyableToOnRight(di))
274                 {
275                         GetItemFileNames(sel, slFile, srFile);
276                         fileOp.AddSourceFile(srFile);
277                 }
278         }
279
280         BOOL bSuccess = FALSE;
281         BOOL bAPICalled = FALSE;
282         BOOL bAborted = FALSE;
283         int  nAPIReturn = 0;
284         bSuccess = fileOp.Go( &bAPICalled, &nAPIReturn, &bAborted );
285 }
286
287 // Confirm with user, then perform the action list
288 void CDirView::ConfirmAndPerformActions(ActionList & actionList)
289 {
290         if (!actionList.selcount) // Not sure it is possible to get right-click menu without
291                 return;    // any selected items, but may as well be safe
292
293         ASSERT(actionList.actions.GetCount()>0); // Or else the update handler got it wrong
294
295         if (!ConfirmActionList(actionList))
296                 return;
297
298         PerformActionList(actionList);
299 }
300
301 /**
302  * @brief Confirm actions with user as appropriate
303  * (type, whether single or multiple).
304  */
305 BOOL CDirView::ConfirmActionList(const ActionList & actionList)
306 {
307         // special handling for the single item case, because it is probably the most common,
308         // and we can give the user exact details easily for it
309         switch(actionList.atype)
310         {
311         case ACT_COPY:
312                 if (actionList.GetCount()==1)
313                 {
314                         const action & act = actionList.actions.GetHead();
315                         if (!ConfirmSingleCopy(act.src, act.dest))
316                                 return FALSE;
317                 }
318                 else
319                 {
320                         if (!ConfirmMultipleCopy(actionList.GetCount(), actionList.selcount))
321                                 return FALSE;
322                 }
323                 break;
324                 
325         // Deleting does not need confirmation, CShellFileOp takes care of it
326         case ACT_DEL_LEFT:
327         case ACT_DEL_RIGHT:
328         case ACT_DEL_BOTH:
329                 break;
330
331         // Invalid operation
332         default: 
333                 LogErrorString(_T("Unknown fileoperation in CDirView::ConfirmActionList()"));
334                 _RPTF0(_CRT_ERROR, "Unknown fileoperation in CDirView::ConfirmActionList()");
335                 break;
336         }
337         return TRUE;
338 }
339
340 /**
341  * @brief Perform an array of actions
342  * @note There can be only COPY or DELETE actions, not both!
343  */
344 void CDirView::PerformActionList(ActionList & actionList)
345 {
346         CShellFileOp fileOp;
347         CString destPath;
348         CString startPath;
349         UINT operation = 0;
350
351         // Set mainframe variable (VSS):
352         mf->m_CheckOutMulti = FALSE;
353         mf->m_bVCProjSync = TRUE;
354         
355         switch (actionList.atype)
356         {
357         case ACT_COPY:
358                 operation = FO_COPY;
359                 break;
360         case ACT_DEL_LEFT:
361                 operation = FO_DELETE;
362                 break;
363         case ACT_DEL_RIGHT:
364                 operation = FO_DELETE;
365                 break;
366         case ACT_DEL_BOTH:
367                 operation = FO_DELETE;
368                 break;
369         default:
370                 LogErrorString(_T("Unknown fileoperation in CDirView::PerformActionList()"));
371                 _RPTF0(_CRT_ERROR, "Unknown fileoperation in CDirView::PerformActionList()");
372                 break;
373         }
374         
375         int operFlags = FOF_NOCONFIRMMKDIR | FOF_MULTIDESTFILES;
376         
377         // Check option and enable putting deleted items to Recycle Bin
378         if (mf->m_options.GetInt(OPT_USE_RECYCLE_BIN) == TRUE)
379                 operFlags |= FOF_ALLOWUNDO;
380         fileOp.SetOperationFlags(operation, this, operFlags);
381         
382         // Add files/directories
383         BOOL bSucceed = TRUE;
384         POSITION pos = actionList.actions.GetHeadPosition();
385         while (bSucceed && pos != NULL)
386         {
387                 const action act = actionList.actions.GetNext(pos);
388
389                 // If copying files, try to sync files to VCS too
390                 if (actionList.atype == ACT_COPY && !act.dirflag)
391                 {
392                         CString strErr;
393                         bSucceed = mf->SyncFilesToVCS(act.src, act.dest, &strErr);
394                         if (!bSucceed)
395                                 AfxMessageBox(strErr, MB_OK | MB_ICONERROR);
396                 }
397
398                 if (bSucceed) // No error from VCS sync (propably just not called)
399                 {
400                         try
401                         {
402                                 switch (actionList.atype)
403                                 {
404                                 case ACT_COPY:
405                                         fileOp.AddSourceFile(act.src);
406                                         fileOp.AddDestFile(act.dest);
407                                         gLog.Write(_T("Copy file(s) from: %s\n\tto: %s"), act.src, act.dest);
408                                         break;
409                                 case ACT_DEL_LEFT:
410                                         fileOp.AddSourceFile(act.src);
411                                         gLog.Write(_T("Delete file(s) from LEFT: %s"), act.src);
412                                         break;
413                                 case ACT_DEL_RIGHT:
414                                         fileOp.AddSourceFile(act.src);
415                                         gLog.Write(_T("Delete file(s) from RIGHT: %s"), act.src);
416                                         break;
417                                 case ACT_DEL_BOTH:
418                                         fileOp.AddSourceFile(act.src);
419                                         fileOp.AddSourceFile(act.dest);
420                                         gLog.Write(_T("Delete BOTH file(s) from: %s\n\tto: %s"), act.src, act.dest);
421                                         break;
422                                 }
423                         }
424                         catch (CMemoryException *ex)
425                         {
426                                 bSucceed = FALSE;
427                                 LogErrorString(_T("CDirView::PerformActionList(): ")
428                                         _T("Adding files to buffer failed!"));
429                                 ex->ReportError();
430                                 ex->Delete();
431                         }
432                 }
433         } 
434
435         // Now process files/directories that got added to list
436         BOOL bOpStarted = FALSE;
437         int apiRetVal = 0;
438         BOOL bUserCancelled = FALSE; 
439         BOOL bFileOpSucceed = fileOp.Go(&bOpStarted, &apiRetVal, &bUserCancelled);
440
441         // All succeeded
442         if (bFileOpSucceed && !bUserCancelled)
443         {
444                 gLog.Write(_T("Fileoperation succeeded."));
445                 UpdateCopiedItems(actionList);
446                 UpdateDeletedItems(actionList);
447         }
448         else if (!bOpStarted)
449         {
450                 // Invalid parameters - is this programmer error only?
451                 LogErrorString(_T("Invalid usage of CShellFileOp in ")
452                         _T("CDirView::PerformActionList()"));
453                 _RPTF0(_CRT_ERROR, "Invalid usage of CShellFileOp in "
454                         "CDirView::PerformActionList()");
455         }
456         else if (bUserCancelled)
457         {
458                 // User cancelled, we have a problem as we don't know which
459                 // items were processed!
460                 // User could cancel operation before it was done or during operation
461                 gLog.Write(LOGLEVEL::LWARNING, _T("User cancelled fileoperation!"));
462         }
463         else
464         {
465                 // CShellFileOp shows errors to user, so just write log
466                 LogErrorString(Fmt(_T("File operation failed: %s"),
467                         GetSysError(GetLastError())));
468         }
469 }
470
471 /**
472  * @brief Update copied items after fileactions
473  */
474 void CDirView::UpdateCopiedItems(ActionList & actionList)
475 {
476         while (actionList.GetCount()>0)
477         {
478                 action act = actionList.actions.RemoveHead();
479                 POSITION diffpos = GetItemKey(act.idx);
480                 const DIFFITEM & di = GetDiffContext()->GetDiffAt(diffpos);
481
482                 if (actionList.atype == ACT_COPY)
483                 {
484                         // Copy files and folders
485                         CDirDoc *pDoc = GetDocument();
486                         pDoc->SetDiffSide(DIFFCODE::BOTH, act.idx);
487                         
488                         // Folders don't have compare flag set!!
489                         if (act.dirflag)
490                                 pDoc->SetDiffCompare(DIFFCODE::NOCMP, act.idx);
491                         else
492                                 pDoc->SetDiffCompare(DIFFCODE::SAME, act.idx);
493                         pDoc->ReloadItemStatus(act.idx);
494                 }
495                 else
496                 {
497                         // Delete files and folders
498                         // If both items or unique item is deleted, don't bother updating
499                         // statuses, just remove from list
500                         CDirDoc *pDoc = GetDocument();
501                         if (actionList.atype == ACT_DEL_LEFT)
502                         {
503                                 if (di.isSideLeft())
504                                 {
505                                         actionList.deletedItems.AddTail(act.idx);
506                                 }
507                                 else
508                                 {
509                                         pDoc->SetDiffSide(DIFFCODE::RIGHT, act.idx);
510                                         pDoc->SetDiffCompare(DIFFCODE::NOCMP, act.idx);
511                                         pDoc->ReloadItemStatus(act.idx);
512                                 }
513                         }
514                         
515                         if (actionList.atype == ACT_DEL_RIGHT)
516                         {
517                                 if (di.isSideRight())
518                                 {
519                                         actionList.deletedItems.AddTail(act.idx);
520                                 }
521                                 else
522                                 {
523                                         pDoc->SetDiffSide(DIFFCODE::LEFT, act.idx);
524                                         pDoc->SetDiffCompare(DIFFCODE::NOCMP, act.idx);
525                                         pDoc->ReloadItemStatus(act.idx);
526                                 }
527                         }
528
529                         if (actionList.atype == ACT_DEL_BOTH)
530                         {
531                                 actionList.deletedItems.AddTail(act.idx);
532                         }
533                 }
534         }
535 }
536
537 /**
538  * @brief Update deleted items after fileactions
539  */
540 void CDirView::UpdateDeletedItems(ActionList & actionList)
541 {
542         while (!actionList.deletedItems.IsEmpty())
543         {
544                 int idx = actionList.deletedItems.RemoveTail();
545                 POSITION diffpos = GetItemKey(idx);
546                 GetDiffContext()->RemoveDiff(diffpos);
547                 m_pList->DeleteItem(idx);
548         }
549
550 }
551
552 /// Get directories of first selected item
553 BOOL CDirView::GetSelectedDirNames(CString& strLeft, CString& strRight) const
554 {
555         BOOL bResult = GetSelectedFileNames(strLeft, strRight);
556
557         if (bResult)
558         {
559                 strLeft = GetPathOnly(strLeft);
560                 strRight = GetPathOnly(strRight);
561         }
562         return bResult;
563 }
564
565 /// is it possible to copy item to left ?
566 BOOL CDirView::IsItemCopyableToLeft(const DIFFITEM & di)
567 {
568         // don't let them mess with error items
569         if (di.isResultError()) return FALSE;
570         // can't copy same items
571         if (di.isResultSame()) return FALSE;
572         // impossible if only on left
573         if (di.isSideLeft()) return FALSE;
574
575         // everything else can be copied to left
576         return TRUE;
577 }
578 /// is it possible to copy item to right ?
579 BOOL CDirView::IsItemCopyableToRight(const DIFFITEM & di)
580 {
581         // don't let them mess with error items
582         if (di.isResultError()) return FALSE;
583         // can't copy same items
584         if (di.isResultSame()) return FALSE;
585         // impossible if only on right
586         if (di.isSideRight()) return FALSE;
587
588         // everything else can be copied to right
589         return TRUE;
590 }
591 /// is it possible to delete left item ?
592 BOOL CDirView::IsItemDeletableOnLeft(const DIFFITEM & di)
593 {
594         // don't let them mess with error items
595         if (di.isResultError()) return FALSE;
596         // impossible if only on right
597         if (di.isSideRight()) return FALSE;
598         // everything else can be deleted on left
599         return TRUE;
600 }
601 /// is it possible to delete right item ?
602 BOOL CDirView::IsItemDeletableOnRight(const DIFFITEM & di)
603 {
604         // don't let them mess with error items
605         if (di.isResultError()) return FALSE;
606         // impossible if only on right
607         if (di.isSideLeft()) return FALSE;
608
609         // everything else can be deleted on right
610         return TRUE;
611 }
612 /// is it possible to delete both items ?
613 BOOL CDirView::IsItemDeletableOnBoth(const DIFFITEM & di)
614 {
615         // don't let them mess with error items
616         if (di.isResultError()) return FALSE;
617         // impossible if only on right or left
618         if (di.isSideLeft() || di.isSideRight()) return FALSE;
619
620         // everything else can be deleted on both
621         return TRUE;
622 }
623
624 /// is it possible to open left item ?
625 BOOL CDirView::IsItemOpenableOnLeft(const DIFFITEM & di)
626 {
627         // impossible if only on right
628         if (di.isSideRight()) return FALSE;
629
630         // everything else can be opened on right
631         return TRUE;
632 }
633 /// is it possible to open right item ?
634 BOOL CDirView::IsItemOpenableOnRight(const DIFFITEM & di)
635 {
636         // impossible if only on left
637         if (di.isSideLeft()) return FALSE;
638
639         // everything else can be opened on left
640         return TRUE;
641 }
642 /// is it possible to open left ... item ?
643 BOOL CDirView::IsItemOpenableOnLeftWith(const DIFFITEM & di)
644 {
645         return (!di.isDirectory() && IsItemOpenableOnLeft(di));
646 }
647 /// is it possible to open with ... right item ?
648 BOOL CDirView::IsItemOpenableOnRightWith(const DIFFITEM & di)
649 {
650         return (!di.isDirectory() && IsItemOpenableOnRight(di));
651 }
652 /// is it possible to copy to... left item?
653 BOOL CDirView::IsItemCopyableToOnLeft(const DIFFITEM & di)
654 {
655         // no directory copying right now
656         if (di.isDirectory()) return FALSE;
657         // impossible if only on right
658         if (di.isSideRight()) return FALSE;
659
660         // everything else can be copied to from left
661         return TRUE;
662 }
663 /// is it possible to copy to... right item?
664 BOOL CDirView::IsItemCopyableToOnRight(const DIFFITEM & di)
665 {
666         // no directory copying right now
667         if (di.isDirectory()) return FALSE;
668         // impossible if only on left
669         if (di.isSideLeft()) return FALSE;
670
671         // everything else can be copied to from right
672         return TRUE;
673 }
674
675 /// get the file names on both sides for first selected item
676 BOOL CDirView::GetSelectedFileNames(CString& strLeft, CString& strRight) const
677 {
678         int sel = m_pList->GetNextItem(-1, LVNI_SELECTED);
679         if (sel == -1)
680                 return FALSE;
681         GetItemFileNames(sel, strLeft, strRight);
682         return TRUE;
683 }
684 /// get file name on specified side for first selected item
685 CString CDirView::GetSelectedFileName(SIDE_TYPE stype) const
686 {
687         CString left, right;
688         if (!GetSelectedFileNames(left, right)) return _T("");
689         return stype==SIDE_LEFT ? left : right;
690 }
691
692 /// get the file names on both sides for specified item
693 void CDirView::GetItemFileNames(int sel, CString& strLeft, CString& strRight) const
694 {
695         CString name, pathex;
696
697         POSITION diffpos = GetItemKey(sel);
698         const CDiffContext * ctxt = GetDiffContext();
699         const DIFFITEM & di = ctxt->GetDiffAt(diffpos);
700
701         CString relpath = paths_ConcatPath(di.sSubdir, di.sfilename);
702         strLeft = paths_ConcatPath(ctxt->m_strLeft, relpath);
703         strRight = paths_ConcatPath(ctxt->m_strRight, relpath);
704 }
705
706 /// Open selected file on specified side
707 void CDirView::DoOpen(SIDE_TYPE stype)
708 {
709         int sel = GetSingleSelectedItem();
710         if (sel == -1) return;
711         CString file = GetSelectedFileName(stype);
712         if (file.IsEmpty()) return;
713         int rtn = (int)ShellExecute(::GetDesktopWindow(), _T("open"), file, 0, 0, SW_SHOWNORMAL);
714         if (rtn==SE_ERR_NOASSOC)
715                 DoOpenWith(stype);
716
717 }
718
719 /// Open with dialog for file on selected side
720 void CDirView::DoOpenWith(SIDE_TYPE stype)
721 {
722         int sel = GetSingleSelectedItem();
723         if (sel == -1) return;
724         CString file = GetSelectedFileName(stype);
725         if (file.IsEmpty()) return;
726         CString sysdir;
727         if (!GetSystemDirectory(sysdir.GetBuffer(MAX_PATH), MAX_PATH)) return;
728         sysdir.ReleaseBuffer();
729         CString arg = (CString)_T("shell32.dll,OpenAs_RunDLL ") + file;
730         ShellExecute(::GetDesktopWindow(), 0, _T("RUNDLL32.EXE"), arg, sysdir, SW_SHOWNORMAL);
731 }
732
733 /// Open selected file  on specified side to external editor
734 void CDirView::DoOpenWithEditor(SIDE_TYPE stype)
735 {
736         int sel = GetSingleSelectedItem();
737         if (sel == -1) return;
738         CString file = GetSelectedFileName(stype);
739         if (file.IsEmpty()) return;
740
741         mf->OpenFileToExternalEditor(file);
742 }