1 /////////////////////////////////////////////////////////////////////////////
2 // WinMerge: an interactive diff/merge utility
3 // Copyright (C) 1997 Dean P. Grimm
4 // SPDX-License-Identifier: GPL-2.0-or-later
5 /////////////////////////////////////////////////////////////////////////////
9 * @brief Declaration of class CDirView
13 /////////////////////////////////////////////////////////////////////////////
18 #include "OptionsDirColors.h"
19 #include "SortHeaderCtrl.h"
20 #include "UnicodeString.h"
21 #include "DirItemIterator.h"
22 #include "DirActions.h"
23 #include "IListCtrlImpl.h"
24 #include "FileOpenFlags.h"
26 class FileActionScript;
28 typedef enum { eMain, eContext } eMenuType;
29 typedef enum { DO_NOT_EXPAND, EXPAND_ALL, EXPAND_DIFFERENT, EXPAND_IDENTICAL } eExpandSubfoldersType;
36 class DirCompProgressBar;
39 class CLoadSaveCodepageDlg;
40 class CShellContextMenu;
42 class DirViewColItems;
43 class DirItemEnumerator;
47 * @brief Position value for special items (..) in directory compare view.
49 const uintptr_t SPECIAL_ITEM_POS = (uintptr_t)(reinterpret_cast<DIFFITEM *>( - 1L));
51 /** Default column width in directory compare */
52 constexpr int DefColumnWidth = 111;
55 * @brief Directory compare results view.
57 * Directory compare view is list-view based, so it shows one result (for
58 * folder or file, commonly called as 'item') in one line. User can select
59 * visible columns, re-order columns, sort by column etc.
61 * Actual data is stored in CDiffContext in CDirDoc. Dircompare items and
62 * CDiffContext items are linked by storing POSITION of CDiffContext item
63 * as CDirView listitem key.
65 class CDirView : public CListView
67 friend struct FileCmpReport;
68 friend DirItemEnumerator;
70 CDirView(); // protected constructor used by dynamic creation
71 DECLARE_DYNCREATE(CDirView)
75 CDirDoc* GetDocument(); // non-debug version is inline
76 // const version, for const methods to be able to call
77 const CDirDoc * GetDocument() const { return const_cast<CDirView *>(this)->GetDocument(); }
78 const CDiffContext& GetDiffContext() const;
79 CDiffContext& GetDiffContext();
80 const DirViewColItems* GetDirViewColItems() const { return m_pColItems.get(); };
84 CDirFrame * GetParentFrame();
86 void StartCompare(CompareStats *pCompareStats);
88 void RedisplayChildren(DIFFITEM *diffpos, int level, UINT &index, int &alldiffs);
89 void UpdateResources();
90 void LoadColumnHeaderItems();
91 DIFFITEM *GetItemKey(int idx) const;
92 int GetItemIndex(DIFFITEM *key);
93 bool IsDiffItemSpecial(const DIFFITEM* diffpos) const { return diffpos == reinterpret_cast<DIFFITEM*>(SPECIAL_ITEM_POS); };
94 // for populating list
95 void DeleteItem(int sel, bool removeDIFFITEM = false);
96 void DeleteAllDisplayItems();
97 void SetFont(const LOGFONT & lf);
99 void SortColumnsAppropriately();
101 UINT GetSelectedCount() const;
102 int GetFirstSelectedInd();
103 void AddParentFolderItem(bool bEnable);
104 void RefreshOptions();
108 void MoveToNextDiff();
109 void MoveToPrevDiff();
112 void OpenFirstFile();
119 void SetActivePane(int pane);
121 // Implementation types
124 // Implementation in DirActions.cpp
126 void GetItemFileNames(int sel, String& strLeft, String& strRight) const;
127 void GetItemFileNames(int sel, PathContext * paths) const;
128 void FormatEncodingDialogDisplays(CLoadSaveCodepageDlg * dlg);
129 DirActions MakeDirActions(DirActions::method_type func) const;
130 DirActions MakeDirActions(DirActions::method_type2 func) const;
131 Counts Count(DirActions::method_type2 func) const;
132 void DoDirAction(DirActions::method_type func, const String& status_message);
133 void DoDirActionTo(SIDE_TYPE stype, DirActions::method_type func, const String& status_message);
134 void DoOpen(SIDE_TYPE stype);
135 void DoOpenWith(SIDE_TYPE stype);
136 void DoOpenWithEditor(SIDE_TYPE stype);
137 void DoOpenParentFolder(SIDE_TYPE stype);
138 void DoUpdateOpen(SELECTIONTYPE selectionType, CCmdUI* pCmdUI, bool openableForDir = true);
139 void ConfirmAndPerformActions(FileActionScript & actions);
140 void PerformActionList(FileActionScript & actions);
141 void UpdateAfterFileScript(FileActionScript & actionList);
142 void DoFileEncodingDialog();
144 // End DirActions.cpp
145 void ReflectGetdispinfo(NMLVDISPINFO *);
147 // Implementation in DirViewColHandler.cpp
149 void UpdateColumnNames();
150 void SetColAlignments();
151 // class CompareState is used to pass parameters to the PFNLVCOMPARE callback function.
155 const DirViewColItems *const pColItems;
156 const CDiffContext *const pCtxt;
158 const bool bSortAscending;
159 const bool bTreeMode;
161 CompareState(const CDiffContext *pCtxt, const DirViewColItems *pColItems, int sortCol, bool bSortAscending, bool bTreeMode);
162 static int CALLBACK CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);
164 void UpdateDiffItemStatus(UINT nIdx);
167 void NameColumn(const DirColInfo *col, int subitem);
168 void AddNewItem(int i, DIFFITEM *diffpos, int iImage, int iIndent);
169 // End DirViewCols.cpp
174 // ClassWizard generated virtual function overrides
175 //{{AFX_VIRTUAL(CDirView)
177 virtual void OnInitialUpdate();
178 virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
180 virtual BOOL PreTranslateMessage(MSG* pMsg);
181 virtual BOOL OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult);
182 virtual BOOL OnChildNotify(UINT, WPARAM, LPARAM, LRESULT*);
183 virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam);
189 int GetFocusedItem();
190 int GetFirstDifferentItem();
191 int GetLastDifferentItem();
192 int AddSpecialItems();
193 std::vector<String> GetCurrentColRegKeys();
194 void OpenSpecialItems(CDirDoc *pDoc, DIFFITEM *pos1, DIFFITEM *pos2, DIFFITEM *pos3);
196 // Implementation data
198 CSortHeaderCtrl m_ctlSortHeader;
199 CImageList m_imageList;
200 CImageList m_imageState;
202 std::unique_ptr<IListCtrl> m_pIList;
203 int m_nEscCloses; /**< Cached value for option for ESC closing window */
204 eExpandSubfoldersType m_nExpandSubdirs;
205 CFont m_font; /**< User-selected font */
206 bool m_bTreeMode; /**< `true` if tree mode is on*/
207 DirViewFilterSettings m_dirfilter;
208 clock_t m_compareStart; /**< Starting process time of the compare */
209 clock_t m_elapsed; /**< Elapsed time of the compare */
210 bool m_bUserCancelEdit; /**< `true` if the user cancels rename */
211 String m_lastCopyFolder; /**< Last Copy To -target folder. */
213 std::vector<ListViewOwnerDataItem> m_listViewItems;
214 std::optional<int> m_firstDiffItem;
215 std::optional<int> m_lastDiffItem;
216 DIRCOLORSETTINGS m_cachedColors; /**< Cached color settings */
219 std::unique_ptr<CShellContextMenu> m_pShellContextMenuLeft; /**< Shell context menu for group of left files */
220 std::unique_ptr<CShellContextMenu> m_pShellContextMenuMiddle; /**< Shell context menu for group of middle files */
221 std::unique_ptr<CShellContextMenu> m_pShellContextMenuRight; /**< Shell context menu for group of right files */
222 HMENU m_hCurrentMenu; /**< Current shell context menu (either left or right) */
223 std::unique_ptr<DirViewTreeState> m_pSavedTreeState;
224 std::unique_ptr<DirViewColItems> m_pColItems;
227 // Generated message map functions
228 afx_msg void OnColumnClick(NMHDR* pNMHDR, LRESULT* pResult);
229 afx_msg void OnContextMenu(CWnd*, CPoint point);
230 //{{AFX_MSG(CDirView)
231 afx_msg void OnLButtonDblClk(UINT nFlags, CPoint point);
232 afx_msg void OnDirCopy(UINT id);
233 template<SIDE_TYPE srctype, SIDE_TYPE dsttype>
234 afx_msg void OnCtxtDirCopy();
235 afx_msg void OnUpdateDirCopy(CCmdUI* pCmdUI);
236 template<SIDE_TYPE srctype, SIDE_TYPE dsttype>
237 afx_msg void OnUpdateCtxtDirCopy(CCmdUI* pCmdUI);
238 template<SIDE_TYPE srctype, SIDE_TYPE dsttype>
239 afx_msg void OnCtxtDirMove();
240 template<SIDE_TYPE srctype, SIDE_TYPE dsttype>
241 afx_msg void OnUpdateCtxtDirMove(CCmdUI* pCmdUI);
242 template<SIDE_TYPE stype>
243 afx_msg void OnCtxtDirDel();
244 template<SIDE_TYPE stype>
245 afx_msg void OnUpdateCtxtDirDel(CCmdUI* pCmdUI);
246 afx_msg void OnCtxtDirDelBoth();
247 afx_msg void OnUpdateCtxtDirDelBoth(CCmdUI* pCmdUI);
248 template<SIDE_TYPE stype>
249 afx_msg void OnCtxtDirOpen() { DoOpen(stype); }
250 template<SIDE_TYPE stype>
251 afx_msg void OnUpdateCtxtDirOpen(CCmdUI* pCmdUI);
252 template<SIDE_TYPE stype>
253 afx_msg void OnCtxtDirOpenWith() { DoOpenWith(stype); }
254 template<SIDE_TYPE stype>
255 afx_msg void OnUpdateCtxtDirOpenWith(CCmdUI* pCmdUI);
256 template<SIDE_TYPE stype>
257 afx_msg void OnCtxtDirOpenWithEditor() { DoOpenWithEditor(stype); }
258 template<SIDE_TYPE stype>
259 afx_msg void OnUpdateCtxtDirOpenWithEditor(CCmdUI* pCmdUI);
260 template<SIDE_TYPE stype>
261 afx_msg void OnCtxtDirOpenParentFolder() { DoOpenParentFolder(stype); }
262 template<SIDE_TYPE stype>
263 afx_msg void OnUpdateCtxtDirOpenParentFolder(CCmdUI* pCmdUI);
264 template<SIDE_TYPE stype>
265 afx_msg void OnCtxtDirCopyTo();
266 template<SIDE_TYPE stype>
267 afx_msg void OnUpdateCtxtDirCopyTo(CCmdUI* pCmdUI);
268 afx_msg void OnUpdateCtxtDirCopyBothTo(CCmdUI* pCmdUI);
269 afx_msg void OnUpdateCtxtDirCopyBothDiffsOnlyTo(CCmdUI* pCmdUI);
270 template<SIDE_TYPE stype>
271 afx_msg void OnUpdateCtxtDirCopy2(CCmdUI* pCmdUI);
272 afx_msg void OnUpdateCtxtDirCopyBoth2(CCmdUI* pCmdUI);
273 afx_msg void OnDestroy();
274 afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags);
275 afx_msg void OnClick(NMHDR* pNMHDR, LRESULT* pResult);
276 afx_msg void OnFirstdiff();
277 afx_msg void OnUpdateFirstdiff(CCmdUI* pCmdUI);
278 afx_msg void OnLastdiff();
279 afx_msg void OnUpdateLastdiff(CCmdUI* pCmdUI);
280 afx_msg void OnNextdiff();
281 afx_msg void OnUpdateNextdiff(CCmdUI* pCmdUI);
282 afx_msg void OnPrevdiff();
283 afx_msg void OnUpdatePrevdiff(CCmdUI* pCmdUI);
284 afx_msg void OnCurdiff();
285 afx_msg void OnUpdateCurdiff(CCmdUI* pCmdUI);
286 afx_msg void OnUpdateSave(CCmdUI* pCmdUI);
287 afx_msg LRESULT OnUpdateUIMessage(WPARAM wParam, LPARAM lParam);
288 afx_msg void OnRefresh();
289 afx_msg void OnUpdateRefresh(CCmdUI* pCmdUI);
290 afx_msg void OnTimer(UINT_PTR nIDEvent);
291 afx_msg void OnEditColumns();
292 template<SIDE_TYPE stype>
293 afx_msg void OnReadOnly();
294 afx_msg void OnUpdateReadOnly(CCmdUI* pCmdUI, SIDE_TYPE stype);
295 template<SIDE_TYPE stype>
296 afx_msg void OnUpdateReadOnly(CCmdUI* pCmdUI) { OnUpdateReadOnly(pCmdUI, stype); }
297 afx_msg void OnUpdateStatusLeftRO(CCmdUI* pCmdUI);
298 afx_msg void OnUpdateStatusMiddleRO(CCmdUI* pCmdUI);
299 afx_msg void OnUpdateStatusRightRO(CCmdUI* pCmdUI);
300 afx_msg void OnCustomizeColumns();
301 afx_msg void OnOpenWithUnpacker();
302 afx_msg void OnUpdateCtxtOpenWithUnpacker(CCmdUI* pCmdUI);
303 afx_msg void OnToolsGenerateReport();
304 afx_msg LRESULT OnGenerateFileCmpReport(WPARAM wParam, LPARAM lParam);
305 afx_msg void OnToolsGeneratePatch();
306 afx_msg void OnCtxtDirZip(int flag);
308 afx_msg void OnCtxtDirZip() { OnCtxtDirZip(flag); }
309 template<SIDE_TYPE stype>
310 afx_msg void OnCtxtDirShellContextMenu() { ShowShellContextMenu(stype); }
311 afx_msg void OnSelectAll();
312 afx_msg void OnUpdateSelectAll(CCmdUI* pCmdUI);
313 afx_msg void OnPluginSettings(UINT nID);
314 afx_msg void OnUpdatePluginMode(CCmdUI* pCmdUI);
315 afx_msg void OnCopyPathnames(SIDE_TYPE side);
316 template<SIDE_TYPE side>
317 afx_msg void OnCopyPathnames() { OnCopyPathnames(side); }
318 afx_msg void OnCopyBothPathnames();
319 afx_msg void OnCopyFilenames();
320 afx_msg void OnUpdateCopyFilenames(CCmdUI* pCmdUI);
321 afx_msg void OnCopyToClipboard(SIDE_TYPE side);
322 template<SIDE_TYPE side>
323 afx_msg void OnCopyToClipboard() { OnCopyToClipboard(side); }
324 afx_msg void OnCopyBothToClipboard();
325 afx_msg void OnCopyAllDisplayedColumns();
326 afx_msg void OnUpdateCopyAllDisplayedColumns(CCmdUI* pCmdUI);
327 afx_msg void OnItemRename();
328 afx_msg void OnUpdateItemRename(CCmdUI* pCmdUI);
329 afx_msg void OnHideFilenames();
330 afx_msg void OnSize(UINT nType, int cx, int cy);
331 template<SIDE_TYPE stype>
332 afx_msg void OnCtxtDirMoveTo();
333 template<SIDE_TYPE stype>
334 afx_msg void OnUpdateCtxtDirMoveTo(CCmdUI* pCmdUI);
335 afx_msg void OnUpdateHideFilenames(CCmdUI* pCmdUI);
336 afx_msg void OnDelete();
337 afx_msg void OnUpdateDelete(CCmdUI* pCmdUI);
338 afx_msg void OnMarkedRescan();
339 afx_msg void OnUpdateStatusNum(CCmdUI* pCmdUI);
340 afx_msg void OnViewShowHiddenItems();
341 afx_msg void OnUpdateViewShowHiddenItems(CCmdUI* pCmdUI);
342 afx_msg void OnViewTreeMode();
343 afx_msg void OnUpdateViewTreeMode(CCmdUI* pCmdUI);
344 afx_msg void OnViewExpandAllSubdirs();
345 afx_msg void OnViewExpandDifferentSubdirs();
346 afx_msg void OnViewExpandIdenticalSubdirs();
347 afx_msg void OnUpdateViewExpandSubdirs(CCmdUI* pCmdUI);
348 afx_msg void OnViewCollapseAllSubdirs();
349 afx_msg void OnUpdateViewCollapseAllSubdirs(CCmdUI* pCmdUI);
350 afx_msg void OnViewSwapPanes(int pane1, int pane2);
351 template <int pane1, int pane2>
352 afx_msg void OnViewSwapPanes() { OnViewSwapPanes(pane1, pane2); }
353 afx_msg void OnUpdateViewSwapPanes(CCmdUI* pCmdUI, int pane1, int pane2);
354 template <int pane1, int pane2>
355 afx_msg void OnUpdateViewSwapPanes(CCmdUI* pCmdUI) { OnUpdateViewSwapPanes(pCmdUI, pane1, pane2); }
356 afx_msg void OnOptionsShowDifferent();
357 afx_msg void OnOptionsShowIdentical();
358 afx_msg void OnOptionsShowUniqueLeft();
359 afx_msg void OnOptionsShowUniqueMiddle();
360 afx_msg void OnOptionsShowUniqueRight();
361 afx_msg void OnOptionsShowBinaries();
362 afx_msg void OnOptionsShowSkipped();
363 afx_msg void OnOptionsShowDifferentLeftOnly();
364 afx_msg void OnOptionsShowDifferentMiddleOnly();
365 afx_msg void OnOptionsShowDifferentRightOnly();
366 afx_msg void OnOptionsShowMissingLeftOnly();
367 afx_msg void OnOptionsShowMissingMiddleOnly();
368 afx_msg void OnOptionsShowMissingRightOnly();
369 afx_msg void OnUpdateOptionsShowdifferent(CCmdUI* pCmdUI);
370 afx_msg void OnUpdateOptionsShowidentical(CCmdUI* pCmdUI);
371 afx_msg void OnUpdateOptionsShowuniqueleft(CCmdUI* pCmdUI);
372 afx_msg void OnUpdateOptionsShowuniquemiddle(CCmdUI* pCmdUI);
373 afx_msg void OnUpdateOptionsShowuniqueright(CCmdUI* pCmdUI);
374 afx_msg void OnUpdateOptionsShowBinaries(CCmdUI* pCmdUI);
375 afx_msg void OnUpdateOptionsShowSkipped(CCmdUI* pCmdUI);
376 afx_msg void OnUpdateOptionsShowDifferentLeftOnly(CCmdUI* pCmdUI);
377 afx_msg void OnUpdateOptionsShowDifferentMiddleOnly(CCmdUI* pCmdUI);
378 afx_msg void OnUpdateOptionsShowDifferentRightOnly(CCmdUI* pCmdUI);
379 afx_msg void OnUpdateOptionsShowMissingLeftOnly(CCmdUI* pCmdUI);
380 afx_msg void OnUpdateOptionsShowMissingMiddleOnly(CCmdUI* pCmdUI);
381 afx_msg void OnUpdateOptionsShowMissingRightOnly(CCmdUI* pCmdUI);
382 afx_msg void OnMergeCompare(UINT nID);
383 template<SELECTIONTYPE seltype>
384 afx_msg void OnMergeCompare2() { OpenSelection(seltype); }
385 afx_msg void OnMergeCompareNonHorizontally();
386 afx_msg void OnMergeCompareAs(UINT nID);
387 afx_msg void OnUpdateMergeCompare(CCmdUI *pCmdUI);
388 template<SELECTIONTYPE seltype>
389 afx_msg void OnUpdateMergeCompare2(CCmdUI* pCmdUI) { DoUpdateOpen(seltype, pCmdUI); }
390 afx_msg void OnUpdateNoUnpacker(CCmdUI* pCmdUI);
391 afx_msg void OnViewCompareStatistics();
392 afx_msg void OnFileEncoding();
393 afx_msg void OnHelp();
394 afx_msg void OnEditCopy();
395 afx_msg void OnEditCut();
396 afx_msg void OnEditPaste();
397 afx_msg void OnEditUndo();
398 afx_msg void OnUpdateEditUndo(CCmdUI* pCmdUI);
399 afx_msg void OnItemChanged(NMHDR* pNMHDR, LRESULT* pResult);
400 afx_msg void OnBeginLabelEdit(NMHDR* pNMHDR, LRESULT* pResult);
401 afx_msg void OnEndLabelEdit(NMHDR* pNMHDR, LRESULT* pResult);
402 afx_msg void OnODFindItem(NMHDR* pNMHDR, LRESULT* pResult);
403 afx_msg void OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult);
404 afx_msg void OnSearch();
405 afx_msg void OnBeginDrag(NMHDR* pNMHDR, LRESULT* pResult);
407 DECLARE_MESSAGE_MAP()
408 bool OnHeaderBeginDrag(LPNMHEADER hdr, LRESULT* pResult);
409 bool OnHeaderEndDrag(LPNMHEADER hdr, LRESULT* pResult);
410 void HideItems(const std::vector<String>& ItemsToHide);
411 bool IsItemToHide(const String& currentItem, const std::vector<String>& ItemsToHide) const;
414 void Open(CDirDoc *pDoc, const PathContext& paths, fileopenflags_t dwFlags[3], FileTextEncoding encoding[3], PackingInfo * infoUnpacker = nullptr);
415 void OpenSelection(CDirDoc *pDoc, SELECTIONTYPE selectionType = SELECTIONTYPE_NORMAL, PackingInfo * infoUnpacker = nullptr, bool openableForDir = true);
416 void OpenSelection(SELECTIONTYPE selectionType = SELECTIONTYPE_NORMAL, PackingInfo * infoUnpacker = nullptr, bool openableForDir = true);
417 void OpenSelectionAs(UINT id);
418 bool GetSelectedItems(int * sel1, int * sel2, int * sel3);
419 void OpenParentDirectory(CDirDoc *pDocOpen);
420 template<SIDE_TYPE srctype, SIDE_TYPE dsttype>
421 void DoUpdateDirCopy(CCmdUI* pCmdUI, eMenuType menuType);
422 template<SIDE_TYPE srctype, SIDE_TYPE dsttype>
423 void DoUpdateDirMove(CCmdUI* pCmdUI, eMenuType menuType);
424 const DIFFITEM &GetDiffItem(int sel) const;
425 DIFFITEM &GetDiffItem(int sel);
426 int GetSingleSelectedItem() const;
427 void MoveFocus(int currentInd, int i, int selCount);
429 void FixReordering();
430 void HeaderContextMenu(CPoint point, int i);
431 void ListContextMenu(CPoint point, int i);
432 bool ListShellContextMenu(SIDE_TYPE side);
433 void ShowShellContextMenu(SIDE_TYPE side);
434 CShellContextMenu* GetCorrespondingShellContextMenu(HMENU hMenu) const;
435 void ReloadColumns();
436 bool IsLabelEdit() const;
437 void CollapseSubdir(int sel);
438 void ExpandSubdir(int sel, bool bRecursive = false);
439 void GetColors(int nRow, int nCol, COLORREF& clrBk, COLORREF& clrText) const;
440 int GetDefColumnWidth() const { return MulDiv(DefColumnWidth, CClientDC(const_cast<CDirView *>(this)).GetDeviceCaps(LOGPIXELSX), 72); };
443 DirItemIterator Begin() const { return DirItemIterator(m_pIList.get()); }
444 DirItemIterator End() const { return DirItemIterator(); }
445 DirItemIterator RevBegin() const { return DirItemIterator(m_pIList.get(), -1, false, true); }
446 DirItemIterator RevEnd() const { return DirItemIterator(); }
447 DirItemIterator SelBegin() const { return DirItemIterator(m_pIList.get(), -1, true); }
448 DirItemIterator SelEnd() const { return DirItemIterator(); }
449 DirItemIterator SelRevBegin() const { return DirItemIterator(m_pIList.get(), -1, true, true); }
450 DirItemIterator SelRevEnd() const { return DirItemIterator(); }
453 #ifndef _DEBUG // debug version in DirView.cpp
454 inline CDirDoc* CDirView::GetDocument()
455 { return reinterpret_cast<CDirDoc*>(m_pDocument); }