Fix typos
[TortoiseGit.git] / src / Git / GitStatusListCtrl.h
blobfb0d71d90d7402386e35bac6c344e50c8db3417e
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2008-2023 - TortoiseGit
4 // Copyright (C) 2003-2008, 2014 - TortoiseSVN
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License
8 // as published by the Free Software Foundation; either version 2
9 // of the License, or (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software Foundation,
18 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #pragma once
21 #include "TGitPath.h"
22 #include "GitStatus.h"
23 #include "Colors.h"
24 #include "ResizableColumnsListCtrl.h"
25 #include "DragDropImpl.h"
26 #include "ReaderWriterLock.h"
28 #define GIT_WC_ENTRY_WORKING_SIZE_UNKNOWN (-1)
30 // these defines must be in the order the columns are inserted!
31 #define GITSLC_COLFILENAME 0x000000002
32 #define GITSLC_COLEXT 0x000000004
33 #define GITSLC_COLSTATUS 0x000000008
34 //#define SVNSLC_COLAUTHOR 0x000000040
35 //#define SVNSLC_COLREVISION 0x000000080
36 //#define SVNSLC_COLDATE 0x000000100
37 #define GITSLC_COLADD 0x000000010
38 #define GITSLC_COLDEL 0x000000020
39 #define GITSLC_COLMODIFICATIONDATE 0x000000040
40 #define GITSLC_COLSIZE 0x000000080
41 #define GITSLC_COLLFSLOCK 0x000000100
42 #define GITSLC_NUMCOLUMNS 9
44 //#define SVNSLC_COLURL 0x000000200
45 //#define SVNSLC_COLCOPYFROM 0x000020000
47 #define GITSLC_SHOWUNVERSIONED CTGitPath::LOGACTIONS_UNVER
48 #define GITSLC_SHOWNORMAL 0x00000000
49 #define GITSLC_SHOWMODIFIED (CTGitPath::LOGACTIONS_MODIFIED)
50 #define GITSLC_SHOWADDED (CTGitPath::LOGACTIONS_ADDED|CTGitPath::LOGACTIONS_COPY)
51 #define GITSLC_SHOWREMOVED CTGitPath::LOGACTIONS_DELETED
52 #define GITSLC_SHOWCONFLICTED CTGitPath::LOGACTIONS_UNMERGED
53 #define GITSLC_SHOWMISSING 0x00000000
54 #define GITSLC_SHOWREPLACED CTGitPath::LOGACTIONS_REPLACED
55 #define GITSLC_SHOWMERGED CTGitPath::LOGACTIONS_MERGED
56 #define GITSLC_SHOWIGNORED CTGitPath::LOGACTIONS_IGNORE
57 #define GITSLC_SHOWOBSTRUCTED 0x00000000
58 #define GITSLC_SHOWEXTERNAL 0x00000000
59 #define GITSLC_SHOWINCOMPLETE 0x00000000
60 #define GITSLC_SHOWINEXTERNALS 0x00000000
61 #define GITSLC_SHOWREMOVEDANDPRESENT 0x00000000
62 #define GITSLC_SHOWDIRECTFILES 0x04000000
63 #define GITSLC_SHOWDIRECTFOLDER 0x00000000
64 #define GITSLC_SHOWEXTERNALFROMDIFFERENTREPO 0x00000000
65 #define GITSLC_SHOWSWITCHED 0x00000000
66 #define GITSLC_SHOWINCHANGELIST 0x00000000
67 #define GITSLC_SHOWASSUMEVALID CTGitPath::LOGACTIONS_ASSUMEVALID
68 #define GITSLC_SHOWSKIPWORKTREE CTGitPath::LOGACTIONS_SKIPWORKTREE
69 #define GITSLC_SHOWLFSLOCKS 0x00200000
71 #define GITSLC_SHOWDIRECTS (GITSLC_SHOWDIRECTFILES | GITSLC_SHOWDIRECTFOLDER)
73 #define GITSLC_SHOWFILES 0x01000000
74 #define GITSLC_SHOWSUBMODULES 0x02000000
75 #define GITSLC_SHOWEVERYTHING 0xffffffff
77 #define GITSLC_SHOWVERSIONED (GITSLC_SHOWNORMAL|GITSLC_SHOWMODIFIED|\
78 GITSLC_SHOWADDED|GITSLC_SHOWREMOVED|GITSLC_SHOWCONFLICTED|GITSLC_SHOWMISSING|\
79 GITSLC_SHOWREPLACED|GITSLC_SHOWMERGED|GITSLC_SHOWIGNORED|GITSLC_SHOWOBSTRUCTED|\
80 GITSLC_SHOWEXTERNAL|GITSLC_SHOWINCOMPLETE|GITSLC_SHOWINEXTERNALS|\
81 GITSLC_SHOWEXTERNALFROMDIFFERENTREPO)
83 #define GITSLC_SHOWVERSIONEDBUTNORMAL (GITSLC_SHOWMODIFIED|GITSLC_SHOWADDED|\
84 GITSLC_SHOWREMOVED|GITSLC_SHOWCONFLICTED|GITSLC_SHOWMISSING|\
85 GITSLC_SHOWREPLACED|GITSLC_SHOWMERGED|GITSLC_SHOWIGNORED|GITSLC_SHOWOBSTRUCTED|\
86 GITSLC_SHOWEXTERNAL|GITSLC_SHOWINCOMPLETE|GITSLC_SHOWINEXTERNALS|\
87 GITSLC_SHOWEXTERNALFROMDIFFERENTREPO)
89 #define GITSLC_SHOWVERSIONEDBUTNORMALANDEXTERNALSFROMDIFFERENTREPOS (GITSLC_SHOWMODIFIED|\
90 GITSLC_SHOWADDED|GITSLC_SHOWREMOVED|GITSLC_SHOWCONFLICTED|GITSLC_SHOWMISSING|\
91 GITSLC_SHOWREPLACED|GITSLC_SHOWMERGED|GITSLC_SHOWIGNORED|GITSLC_SHOWOBSTRUCTED|\
92 GITSLC_SHOWINCOMPLETE|GITSLC_SHOWEXTERNAL|GITSLC_SHOWINEXTERNALS)
94 #define GITSLC_SHOWVERSIONEDBUTNORMALANDEXTERNALS (GITSLC_SHOWMODIFIED|\
95 GITSLC_SHOWADDED|GITSLC_SHOWREMOVED|GITSLC_SHOWCONFLICTED|GITSLC_SHOWMISSING|\
96 GITSLC_SHOWREPLACED|GITSLC_SHOWMERGED|GITSLC_SHOWIGNORED|GITSLC_SHOWOBSTRUCTED|\
97 GITSLC_SHOWINCOMPLETE)
99 #define GITSLC_SHOWALL (GITSLC_SHOWVERSIONED|GITSLC_SHOWUNVERSIONED)
101 #define GITSLC_POPALL 0xFFFFFFFFFFFFFFFF
102 #define GITSLC_POPCOMPAREWITHBASE CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_COMPARE)
103 #define GITSLC_POPCOMPARE CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_COMPAREWC)
104 #define GITSLC_POPGNUDIFF CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_GNUDIFF1)
105 #define GITSLC_POPREVERT CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_REVERT)
106 #define GITSLC_POPSHOWLOG CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_LOG)
107 #define GITSLC_POPSHOWLOGSUBMODULE CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_LOGSUBMODULE)
108 #define GITSLC_POPSHOWLOGOLDNAME CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_LOGOLDNAME)
109 #define GITSLC_POPOPEN CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_OPEN)
110 #define GITSLC_POPDELETE CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_DELETE)
111 #define GITSLC_POPADD CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_ADD)
112 #define GITSLC_POPIGNORE CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_IGNORE)
113 #define GITSLC_POPCONFLICT CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_EDITCONFLICT)
114 #define GITSLC_POPRESOLVE CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_RESOLVECONFLICT)
115 #define GITSLC_POPEXPLORE CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_EXPLORE)
116 #define GITSLC_POPCOMMIT CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_COMMIT)
117 #define GITSLC_POPCHANGELISTS CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_CHECKGROUP)
118 #define GITSLC_POPBLAME CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_BLAME)
119 #define GITSLC_POPSAVEAS CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_SAVEAS)
120 #define GITSLC_POPCOMPARETWOFILES CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_COMPARETWOFILES)
121 #define GITSLC_POPRESTORE CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_POPRESTORE)
122 #define GITSLC_POPASSUMEVALID CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_ASSUMEVALID)
123 #define GITSLC_POPSKIPWORKTREE CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_SKIPWORKTREE)
124 #define GITSLC_POPEXPORT CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_EXPORT)
125 #define GITSLC_POPUNSETIGNORELOCALCHANGES CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_UNSETIGNORELOCALCHANGES)
126 #define GITSLC_POPPREPAREDIFF CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_PREPAREDIFF)
127 #define GITSLC_POPLFSLOCK CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_LFSLOCK)
128 #define GITSLC_POPLFSUNLOCK CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_LFSUNLOCK)
130 #define GITSLC_IGNORECHANGELIST L"ignore-on-commit"
132 #define OVL_RESTORE 1
134 using GENERICCOMPAREFN = int (__cdecl*)(const void * elem1, const void * elem2);
136 class CGitStatusListCtrlDropTarget;
137 class CIconMenu;
140 * \ingroup TortoiseProc
141 * Simple utility class that defines the sort column order.
143 class CSorter
145 public:
147 CSorter ( ColumnManager* columnManager
148 , int sortedColumn
149 , bool ascending);
151 bool operator() ( const CTGitPath* entry1
152 , const CTGitPath* entry2) const;
154 static int A2L(const CString &str)
156 if (str == L"-")
157 return -1;
159 if (str.IsEmpty())
160 return -2;
162 return _wtol(str);
165 private:
167 ColumnManager* columnManager = nullptr;
168 int sortedColumn = 0;
169 bool ascending = true;
170 bool s_bSortLogical = true;
174 * \ingroup SVN
175 * A List control, based on the MFC CListCtrl which shows a list of
176 * files with their git status. The control also provides a context
177 * menu to do some git tasks on the selected files.
179 * This is the main control used in many dialogs to show a list of files to
180 * work on.
182 class CGitStatusListCtrl :
183 public CResizableColumnsListCtrl<CListCtrl>
185 public:
186 enum
188 IDGITLC_REVERT = 1,
189 /** Compare with base version. when current version is zero (i.e. working tree changes), compare working tree and HEAD */
190 IDGITLC_COMPARE,
191 IDGITLC_OPEN,
192 IDGITLC_DELETE,
193 IDGITLC_IGNORE,
194 /** Compare with base version and generate unified diff. when current version is zero (i.e. working tree changes), compare working tree and HEAD */
195 IDGITLC_GNUDIFF1 ,
196 IDGITLC_LOG ,
197 IDGITLC_LOGOLDNAME,
198 IDGITLC_LOGSUBMODULE,
199 IDGITLC_EDITCONFLICT ,
200 IDGITLC_IGNOREMASK ,
201 IDGITLC_IGNOREFOLDER ,
202 IDGITLC_ADD ,
203 IDGITLC_RESOLVECONFLICT ,
204 IDGITLC_OPENWITH ,
205 IDGITLC_EXPLORE ,
206 IDGITLC_RESOLVETHEIRS ,
207 IDGITLC_RESOLVEMINE ,
208 IDGITLC_REMOVE ,
209 IDGITLC_COMMIT ,
210 IDGITLC_COPYRELPATHS ,
211 IDGITLC_COPYEXT ,
212 IDGITLC_REMOVEFROMCS ,
213 IDGITLC_CREATECS ,
214 IDGITLC_CREATEIGNORECS ,
215 IDGITLC_KEEPCHANGELISTS ,
216 IDGITLC_CHECKGROUP ,
217 IDGITLC_UNCHECKGROUP ,
218 /** Compare current version and working tree */
219 IDGITLC_COMPAREWC ,
220 IDGITLC_COMPAREPARENTWC ,
221 IDGITLC_BLAME ,
222 IDGITLC_SAVEAS ,
223 IDGITLC_REVERTTOREV ,
224 IDGITLC_REVERTTOPARENT ,
225 IDGITLC_VIEWREV ,
226 IDGITLC_FINDENTRY ,
227 /** used in sync dlg, compare in/out file changes; in combination with m_Rev1 and m_Rev2 */
228 IDGITLC_COMPARETWOREVISIONS,
229 /** used in sync dlg, compare in/out file changes; in combination with m_Rev1 and m_Rev2 */
230 IDGITLC_GNUDIFF2REVISIONS,
231 /** Compare two selected files */
232 IDGITLC_COMPARETWOFILES ,
233 IDGITLC_POPRESTORE ,
234 IDGITLC_CREATERESTORE ,
235 IDGITLC_RESTOREPATH ,
236 IDGITLC_ASSUMEVALID ,
237 IDGITLC_SKIPWORKTREE ,
238 IDGITLC_EXPORT ,
239 IDGITLC_UNSETIGNORELOCALCHANGES,
240 IDGITLC_PREPAREDIFF ,
241 IDGITLC_PREPAREDIFF_COMPARE,
242 IDGITLC_COPYCOL ,
243 IDGITLC_COPYFULL ,
244 IDGITLC_COPYFILENAMES ,
245 IDGITLC_ADD_EXE ,
246 IDGITLC_ADD_LINK ,
247 /** LFS Locking **/
248 IDGITLC_LFSLOCK ,
249 IDGITLC_LFSUNLOCK ,
250 // the IDSVNLC_MOVETOCS *must* be the last index, because it contains a dynamic submenu where
251 // the submenu items get command ID's sequent to this number
252 IDGITLC_MOVETOCS ,
254 static_assert(IDGITLC_MOVETOCS < 64, "IDs must be <64 in order to be usable in a bitfield");
255 int GetColumnIndex(int colmask);
256 static constexpr unsigned __int64 GetContextMenuBit(int i) noexcept { return static_cast<unsigned __int64>(0x1) << i; }
258 * Sent to the parent window (using ::SendMessage) after a context menu
259 * command has finished if the item count has changed.
261 static const UINT GITSLNM_ITEMCOUNTCHANGED;
263 * Sent to the parent window (using ::SendMessage) when the control needs
264 * to be refreshed. Since this is done usually in the parent window using
265 * a thread, this message is used to tell the parent to do exactly that.
267 static const UINT GITSLNM_NEEDSREFRESH;
270 * Sent to the parent window (using ::SendMessage) when the user drops
271 * files on the control. The LPARAM is a pointer to a wchar_t string
272 * containing the dropped path.
274 static const UINT GITSLNM_ADDFILE;
277 * Sent to the parent window (using ::SendMessage) when the user checks/unchecks
278 * one or more items in the control. The WPARAM contains the number of
279 * checked items in the control.
281 static const UINT GITSLNM_CHECKCHANGED;
283 static const UINT GITSLNM_ITEMCHANGED;
285 CGitStatusListCtrl();
286 ~CGitStatusListCtrl();
288 HWND GetParentHWND();
290 CGitHash m_Rev1;
291 CGitHash m_Rev2;
294 * \ingroup TortoiseProc
295 * Helper class for CGitStatusListCtrl which represents
296 * the data for each file shown.
298 #if 0
299 class FileEntry
301 public:
302 FileEntry() : status(git_wc_status_unversioned)
303 // , copyfrom_rev(GIT_REV_ZERO)
304 , last_commit_date(0)
305 , last_commit_rev(GIT_REV_ZERO)
306 // , remoterev(GIT_REV_ZERO)
307 , textstatus(git_wc_status_unversioned)
308 , propstatus(git_wc_status_unversioned)
309 // , remotestatus(git_wc_status_unversioned)
310 // , remotetextstatus(git_wc_status_unversioned)
311 // , remotepropstatus(git_wc_status_unversioned)
312 , copied(false)
313 , switched(false)
314 , checked(false)
315 , inunversionedfolder(false)
316 , inexternal(false)
317 , differentrepo(false)
318 , direct(false)
319 , isfolder(false)
320 , isNested(false)
321 , Revision(GIT_REV_ZERO)
322 , isConflicted(false)
323 // , present_props()
324 /// , working_size(SVN_WC_ENTRY_WORKING_SIZE_UNKNOWN)
325 // , depth(git_depth_unknown)
328 const CTGitPath& GetPath() const
330 return path;
332 const bool IsChecked() const
334 return checked;
336 CString GetRelativeGitPath() const
338 if (path.IsEquivalentTo(basepath))
339 return path.GetGitPathString();
340 return path.GetGitPathString().Mid(basepath.GetGitPathString().GetLength()+1);
342 const bool IsFolder() const
344 return isfolder;
346 const bool IsInExternal() const
348 return inexternal;
350 const bool IsNested() const
352 return isNested;
354 const bool IsFromDifferentRepository() const
356 return differentrepo;
358 CString GetDisplayName() const
360 CString const& chopped = path.GetDisplayString(&basepath);
361 if (!chopped.IsEmpty())
363 return chopped;
365 else
367 // "Display name" must not be empty.
368 return path.GetFileOrDirectoryName();
371 CString GetChangeList() const
373 return changelist;
375 // CString GetURL() const
376 // {
377 // return url;
378 // }
379 public:
380 git_wc_status_kind status; ///< local status
381 git_wc_status_kind textstatus; ///< local text status
382 git_wc_status_kind propstatus; ///< local property status
384 private:
385 CTGitPath path; ///< full path of the file
386 CTGitPath basepath; ///< common ancestor path of all files
388 CString changelist; ///< the name of the changelist the item belongs to
390 CString last_commit_author; ///< the author which last committed this item
391 CTime last_commit_date; ///< the date when this item was last committed
392 git_revnum_t last_commit_rev; ///< the revision where this item was last committed
394 git_revnum_t remoterev; ///< the revision in HEAD of the repository
395 bool copied; ///< if the file/folder is added-with-history
396 bool switched; ///< if the file/folder is switched to another url
397 bool checked; ///< if the file is checked in the list control
398 bool inunversionedfolder; ///< if the file is inside an unversioned folder
399 bool inexternal; ///< if the item is in an external folder
400 bool differentrepo; ///< if the item is from a different repository than the rest
401 bool direct; ///< directly included (TRUE) or just a child of a folder
402 bool isfolder; ///< TRUE if entry refers to a folder
403 bool isNested; ///< TRUE if the folder from a different repository and/or path
404 bool isConflicted; ///< TRUE if a file entry is conflicted, i.e. if it has the conflicted paths set
405 git_revnum_t Revision; ///< the base revision
406 // PropertyList present_props; ///< cacheable properties present in BASE
407 git_depth_t depth; ///< the depth of this entry
408 friend class CGitStatusListCtrl;
409 friend class CGitStatusListCtrlDropTarget;
410 friend class CSorter;
412 #endif
415 * Initializes the control, sets up the columns.
416 * \param dwColumns mask of columns to show. Use the GitSLC_COLxxx defines.
417 * \param sColumnInfoContainer Name of a registry key
418 * where the position and visibility of each column
419 * is saved and used from. If the registry key
420 * doesn't exist, the default order is used
421 * and dwColumns tells which columns are visible.
422 * \param dwContextMenus mask of context menus to be active, not all make sense for every use of this control.
423 * Use the GitSLC_POPxxx defines.
424 * \param bHasCheckboxes TRUE if the control should show check boxes on the left of each file entry.
425 * \param bHasWC TRUE if the reporisty is not a bare repository (hides wc related items on the contextmenu)
427 void Init(DWORD dwColumns, const CString& sColumnInfoContainer, unsigned __int64 dwContextMenus, bool bHasCheckboxes = true, bool bHasWC = true, DWORD allowedColumns = 0xffffffff);
428 void EnableThreeStateCheckboxes(bool enable);
430 * Sets a background image for the list control.
431 * The image is shown in the right bottom corner.
432 * \param nID the resource ID of the bitmap to use as the background
434 bool SetBackgroundImage(UINT nID);
436 * Makes the 'ignore' context menu only ignore the files and not add the
437 * folder which gets the Git:ignore property changed to the list.
438 * This is needed e.g. for the Add-dialog, where the modified folder
439 * showing up would break the resulting "add" command.
441 void SetIgnoreRemoveOnly(bool bRemoveOnly = true) {m_bIgnoreRemoveOnly = bRemoveOnly;}
443 * The unversioned items are by default shown after all other files in the list.
444 * If that behavior should be changed, set this value to false.
446 void PutUnversionedLast(bool bLast) {m_bUnversionedLast = bLast;}
448 * Fetches the git status of all files and stores the information
449 * about them in an internal array.
450 * \param sFilePath path to a file which contains a list of files and/or folders for which to
451 * fetch the status, separated by newlines.
452 * \param bUpdate TRUE if the remote status is requested too.
453 * \return TRUE on success.
455 BOOL GetStatus (const CTGitPathList* pathList = nullptr
456 , bool bUpdate = false
457 , bool bShowIgnores = false
458 , bool bShowUnRev = false
459 , bool bShowLocalChangesIgnored = false
460 , bool bShowLFSLocks = false
461 , bool bGetStagingStatus = false);
464 * Populates the list control with the previously (with GetStatus) gathered status information.
465 * \param dwShow mask of file types to show. Use the GitSLC_SHOWxxx defines.
466 * \param dwCheck mask of file types to check. Use GitLC_SHOWxxx defines. Default (0) means 'use the entry's stored check status'
468 void Show(unsigned int dwShow, unsigned int dwCheck = 0, bool bShowFolders = true,BOOL updateStatusList=FALSE, bool UseStoredCheckStatus=false);
470 void AppendLFSLocks(bool onlyExisting);
473 * Copies the selected entries in the control to the clipboard. The entries
474 * are separated by newlines.
475 * \param dwCols the columns to copy. Each column is separated by a tab.
477 bool CopySelectedEntriesToClipboard(DWORD dwCols, int cmd);
480 * If unversioned files are found (but not necessarily shown) TRUE is returned.
482 BOOL HasUnversionedItems() const { return m_bHasUnversionedItems; }
485 * If there are any change lists defined in the working copy, TRUE is returned
487 BOOL HasChangeLists() const {return m_bHasChangeLists;}
490 * Returns the file entry data for the list control index.
492 CTGitPath* GetListEntry(int index);
495 * Returns the file entry data for the specified path.
496 * \note The entry might not be shown in the list control.
498 //CGitStatusListCtrl::FileEntry * GetListEntry(const CTGitPath& path);
501 * Returns the file entry data for the specified path in the list control.
503 //CGitStatusListCtrl::FileEntry * GetVisibleListEntry(const CTGitPath& path);
506 * Returns a String containing some statistics like number of modified, normal, deleted,...
507 * files.
509 CString GetStatisticsString(bool simple=false);
512 * Set a static control which will be updated automatically with
513 * the number of selected and total files shown in the list control.
515 void SetStatLabel(CWnd * pStatLabel){m_pStatLabel = pStatLabel;};
518 * Set a tri-state checkbox which is updated automatically if the
519 * user checks/unchecks file entries in the list control to indicate
520 * if all files are checked, none are checked or some are checked.
522 void SetSelectButton(CButton * pButton) {m_pSelectButton = pButton;}
525 * Set a button which is de-/activated automatically. The button is
526 * only set active if at least one item is selected.
528 void SetConfirmButton(CButton * pButton) {m_pConfirmButton = pButton;}
531 * Select/unselect all entries in the list control.
532 * \param bSelect TRUE to check, FALSE to uncheck.
534 void SelectAll(bool bSelect, bool bIncludeNoCommits = false);
537 * Checks or unchecks all specified items
538 * \param dwCheck GITLC_SHOWxxx defines
539 * \param check if true matching items will be selected, false unchecks matching items
541 void Check(DWORD dwCheck, bool check = true);
543 /** Set a checkbox on an entry in the listbox
544 * Keeps the listctrl checked state and the FileEntry's checked flag in sync
546 void SetEntryCheck(CTGitPath* pEntry, int listboxIndex, bool bCheck);
548 void ResetChecked(const CTGitPath& entry);
550 /** Write a list of the checked items' paths into a path list
552 void WriteCheckedNamesToPathList(CTGitPathList& pathList);
555 * Returns the parent directory of all entries in the control.
556 * if \a bStrict is set to false, then the paths passed to the control
557 * to fetch the status (in GetStatus()) are used if possible.
559 CString GetCommonDirectory(bool bStrict);
562 * Sets a pointer to a boolean variable which is checked periodically
563 * during the status fetching. As soon as the variable changes to true,
564 * the operations stops.
566 void SetCancelBool(bool * pbCanceled) {m_pbCanceled = pbCanceled;}
569 * Sets the string shown in the control while the status is fetched.
570 * If not set, it defaults to "please wait..."
572 void SetBusyString(const CString& str) {m_sBusy = str;}
573 void SetBusyString(UINT id) {m_sBusy.LoadString(id);}
576 * Sets the string shown in the control if no items are shown. This
577 * can happen for example if there's nothing modified and the unversioned
578 * files aren't shown either, so there's nothing to commit.
579 * If not set, it defaults to "file list is empty".
581 void SetEmptyString(const CString& str) {m_sEmpty = str;}
582 void SetEmptyString(UINT id) {m_sEmpty.LoadString(id);}
585 * Returns the number of selected items
587 LONG GetSelected() const { return m_nSelected; };
590 * Enables dropping of files on the control.
592 bool EnableFileDrop();
595 * Checks if the path already exists in the list.
597 bool HasPath(const CTGitPath& path);
600 * Forces the children to be checked when the parent folder is checked,
601 * and the parent folder to be unchecked if one of its children is unchecked.
603 void CheckChildrenWithParent(bool bCheck) {m_bCheckChildrenWithParent = bCheck;}
606 * Allows checking the items if change lists are present. If set to false,
607 * items are not checked if at least one changelist is available.
609 void CheckIfChangelistsArePresent(bool bCheck) {m_bCheckIfGroupsExist = bCheck;}
611 * Returns the currently used show flags passed to the Show() method.
613 DWORD GetShowFlags() const { return m_dwShow; }
615 public:
616 CString GetLastErrorMessage() const { return m_sLastError; }
618 void BusyCursor(bool bBusy) { m_bWaitCursor = bBusy; }
620 LONG GetUnversionedCount() const { return m_nShownUnversioned; }
621 LONG GetModifiedCount() const { return m_nShownModified; }
622 LONG GetAddedCount() const { return m_nShownAdded; }
623 LONG GetDeletedCount() const { return m_nShownDeleted; }
624 LONG GetConflictedCount() const { return m_nShownConflicted; }
625 LONG GetFileCount() const { return m_nShownFiles; }
626 LONG GetSubmoduleCount() const { return m_nShownSubmodules; }
628 CAutoReadLock AcquireReadLock() { return CAutoReadLock(m_guard); }
629 CAutoReadWeakLock AcquireReadWeakLock(DWORD timeout) { return CAutoReadWeakLock(m_guard, timeout); }
631 LONG m_nTargetCount = 0; ///< number of targets in the file passed to GetStatus()
633 CString m_sURL; ///< the URL of the target or "(multiple targets)"
635 bool m_amend = false; ///< if true show the changes to the revision before the last commit
637 bool m_bIncludedStaged = false;
639 CString m_sUUID; ///< the UUID of the associated repository
641 CString m_sDisplayedBranch; ///< When on LogDialog, what is the current displayed branch
643 CWnd* m_hwndLogicalParent = nullptr;
645 DECLARE_MESSAGE_MAP()
647 public:
648 void SetBusy(bool b) {m_bBusy = b; Invalidate();}
649 bool IsBusy() const { return m_bBusy; }
650 void SetHasCheckboxes(bool bHasCheckboxes)
652 m_bHasCheckboxes = bHasCheckboxes;
653 DWORD exStyle = GetExtendedStyle();
654 if (bHasCheckboxes)
655 exStyle |= LVS_EX_CHECKBOXES;
656 else
657 exStyle &= ~LVS_EX_CHECKBOXES;
658 SetExtendedStyle(exStyle);
661 void SetHideTooManyItems(bool b) { m_bHideTooManyItems = b; Invalidate(); }
663 private:
664 CString GetCellText(int listIndex, int column); ///< get the text for a certain grid cell
665 //void AddEntry(FileEntry * entry, WORD langID, int listIndex); ///< add an entry to the control
666 void RemoveListEntry(int index); ///< removes an entry from the listcontrol and both arrays
667 void BuildStatistics(); ///< build the statistics and correct the case of files/folders
668 void StartDiff(int fileindex); ///< start the external diff program
669 void StartDiffWC(int fileindex, bool parent = false); ///< start the external diff program
670 void StartDiffTwo(int fileindex);
672 void SetGitIndexFlagsForSelectedFiles(UINT message, BOOL assumevalid, BOOL skipworktree);
674 void UpdateDiffWithFileFromReg();
675 CString m_sMarkForDiffFilename;
676 CString m_sMarkForDiffVersion;
678 /* while rebasing, Their and My versios are swapped. */
679 bool m_bIsRevertTheirMy = false;
681 enum
683 ALTERNATIVEEDITOR,
684 OPEN,
685 OPEN_WITH,
687 void OpenFile(const CTGitPath* path, int mode);
689 /// Clear the status vector (contains custodial pointers)
690 void ClearStatusArray();
692 /// Sort predicate function - Compare the paths of two entries without regard to case
693 //static bool EntryPathCompareNoCase(const FileEntry* pEntry1, const FileEntry* pEntry2);
695 /// Predicate used to build a list of only the versioned entries of the FileEntry array
696 //static bool IsEntryVersioned(const FileEntry* pEntry1);
698 /// Look up the relevant show flags for a particular Git status value
699 DWORD GetShowFlagsFromGitStatus(git_wc_status_kind status);
701 /// Adjust the checkbox-state on all descendants of a specific item
702 //void SetCheckOnAllDescendentsOf(const FileEntry* parentEntry, bool bCheck);
704 /// Build a path list of all the selected items in the list (NOTE - SELECTED, not CHECKED)
705 void FillListOfSelectedItemPaths(CTGitPathList& pathList, bool bNoIgnored = false);
707 /// Enables/Disables group view and adds all groups to the list control.
708 /// If bForce is true, then group view is enabled and the 'null' group is added.
709 bool PrepareGroups(bool bForce = false);
710 /// Returns the group number to which the group header belongs
711 /// If the point is not over a group header, -1 is returned
712 int GetGroupFromPoint(POINT * ppt);
714 /// Returns the number of change lists the selection has
715 bool HasChangelistInSelection();
716 void MoveToChangelist(const CString& name);
717 void RemoveFromChangelist();
718 void LoadChangelists();
720 void OnColumnVisibilityChanged(int column, bool visible);
721 void RefreshParent();
723 public:
724 void SaveChangelists();
725 void PruneChangelists(const CTGitPathList* root);
726 bool KeepChangeList() const { return m_bKeepChangeLists; };
728 private:
729 int GetChangeListIdForPath(const CTGitPath* pGitPath);
731 // Determines group and puts the item to the group
732 bool SetItemGroup(int item, const CTGitPath* pGitPath);
734 void CheckEntry(int index, int nListItems);
735 void UncheckEntry(int index, int nListItems);
737 /// sends an GitSLNM_CHECKCHANGED notification to the parent
738 void NotifyCheck();
739 CWnd* GetLogicalParent() { return m_hwndLogicalParent ? m_hwndLogicalParent : this->GetParent(); }
741 void OnContextMenuList(CWnd * pWnd, CPoint point);
742 void OnContextMenuGroup(CWnd * pWnd, CPoint point);
743 bool CheckMultipleDiffs();
745 void AppendLocksMenuItems(CIconMenu& popup);
747 void DeleteSelectedFiles();
749 void PreSubclassWindow() override;
750 BOOL PreTranslateMessage(MSG* pMsg) override;
751 BOOL OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult) override;
752 ULONG GetGestureStatus(CPoint ptTouch) override;
753 afx_msg void OnBeginDrag(NMHDR* pNMHDR, LRESULT* pResult);
754 afx_msg void OnHdnItemclick(NMHDR *pNMHDR, LRESULT *pResult);
755 afx_msg BOOL OnLvnItemchanged(NMHDR *pNMHDR, LRESULT *pResult);
756 afx_msg void OnContextMenu(CWnd* pWnd, CPoint point);
758 afx_msg void OnNMDblclk(NMHDR *pNMHDR, LRESULT *pResult);
759 afx_msg void OnLvnGetInfoTip(NMHDR *pNMHDR, LRESULT *pResult);
760 afx_msg BOOL OnNMCustomdraw(NMHDR* pNMHDR, LRESULT* pResult);
761 afx_msg void OnLvnGetdispinfo(NMHDR* pNMHDR, LRESULT* pResult);
762 afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message);
763 afx_msg UINT OnGetDlgCode();
764 afx_msg void OnNMReturn(NMHDR *pNMHDR, LRESULT *pResult);
765 afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
766 afx_msg void OnPaint();
768 void FilesExport();
769 void FileSaveAs(const CTGitPath* path);
770 int RevertSelectedItemToVersion(bool parent = false);
771 bool GetParentCommitInfo(const CGitHash& hash, const int parentNo, CGitHash& parentHash, CString& title);
773 private:
774 bool* m_pbCanceled = nullptr;
775 bool m_bAscending = false; ///< sort direction
776 int m_nSortedColumn = -1; ///< which column to sort
777 bool m_bHasCheckboxes = false;
778 bool m_bHasWC = true;
779 bool m_bUnversionedLast = true;
780 BOOL m_bHasUnversionedItems = FALSE;
781 bool m_bHasChangeLists = false;
782 bool m_bKeepChangeLists = false;
783 CRegDWORD m_regKeepChangeLists;
784 //typedef std::vector<FileEntry*> FileEntryVector;
785 //FileEntryVector m_arStatusArray;
786 std::vector<const CTGitPath*> m_arStatusArray;
787 std::vector<size_t> m_arListArray;
788 std::map<CString, int> m_changelists; // maps changelist to group index
789 std::map<CString, CString> m_pathToChangelist; // maps gitpath to changelist
790 bool m_bHasIgnoreGroup = false;
791 CTGitPathList m_StatusFileList;
792 CTGitPathList m_UnRevFileList;
793 CTGitPathList m_LocksFileList;
794 CTGitPathList m_IgnoreFileList;
795 CTGitPathList m_LocalChangesIgnoredFileList; // assume valid & skip worktree
796 CString m_sLastError;
798 LONG m_nUnversioned = 0;
799 LONG m_nNormal = 0;
800 LONG m_nModified = 0;
801 LONG m_nAdded = 0;
802 LONG m_nDeleted = 0;
803 LONG m_nConflicted = 0;
804 LONG m_nTotal = 0;
805 LONG m_nSelected = 0;
806 LONG m_nLineAdded = 0;
807 LONG m_nLineDeleted = 0;
808 LONG m_nRenamed = 0;
810 LONG m_nShownUnversioned = 0;
811 LONG m_nShownModified = 0;
812 LONG m_nShownAdded = 0;
813 LONG m_nShownDeleted = 0;
814 LONG m_nShownConflicted = 0;
815 LONG m_nShownFiles = 0;
816 LONG m_nShownSubmodules = 0;
818 DWORD m_dwDefaultColumns = 0;
819 DWORD m_dwShow = 0;
820 bool m_bShowFolders = false;
821 bool m_bShowIgnores = false;
822 bool m_bHideTooManyItems = false;
823 bool m_bTooManyItems = false;
824 bool m_bUpdate = false;
825 unsigned __int64 m_dwContextMenus = 0;
826 bool m_bBusy = false;
827 bool m_bWaitCursor = false;
828 bool m_bEmpty = false;
829 bool m_bIgnoreRemoveOnly = false;
830 bool m_bCheckIfGroupsExist = true;
831 bool m_bFileDropsEnabled = false;
832 bool m_bOwnDrag = false;
834 int m_nIconFolder = 0;
835 int m_nRestoreOvl = 0;
837 CWnd* m_pStatLabel = nullptr;
838 CButton* m_pSelectButton = nullptr;
839 CButton* m_pConfirmButton = nullptr;
840 CColors m_Colors;
842 CString m_sEmpty;
843 CString m_sBusy;
844 CString m_sTooManyItems;
846 DWORD m_nTooManyItemsThreshold = 1000;
848 bool m_bCheckChildrenWithParent = false;
849 std::unique_ptr<CGitStatusListCtrlDropTarget> m_pDropTarget;
850 volatile LONG m_nBlockItemChangeHandler = FALSE;
851 std::map<CString,bool> m_mapFilenameToChecked; ///< Remember de-/selected items
852 std::set<CString> m_setDirectFiles;
854 friend class CGitStatusListCtrlDropTarget;
855 public:
856 enum
858 FILELIST_MODIFY= 0x1,
859 FILELIST_UNVER = 0x2,
860 FILELIST_IGNORE =0x4,
861 FILELIST_LOCALCHANGESIGNORED = 0x8, // assume valid & skip worktree files
862 FILELIST_LOCKS = 0x10,
864 private:
865 int UpdateFileList(const CTGitPathList* list = nullptr, bool getStagingStatus = false);
866 public:
867 int UpdateFileList(int mask, bool once = true, const CTGitPathList* list = nullptr, bool getStagingStatus = false);
868 int InsertUnRevListFromPreCalculatedList(const CTGitPathList& list);
869 int UpdateUnRevFileList(const CTGitPathList* list = nullptr);
870 int UpdateLFSLockedFileList(bool onlyExisting);
871 int UpdateIgnoreFileList(const CTGitPathList* list = nullptr);
872 int UpdateLocalChangesIgnoredFileList(const CTGitPathList* list = nullptr);
874 int UpdateWithGitPathList(CTGitPathList &list);
876 void AddEntry(size_t arStatusArrayIndex, CTGitPath* path, WORD langID, int ListIndex);
877 void Clear();
878 int m_FileLoaded = 0;
879 CGitHash m_CurrentVersion;
880 bool m_bDoNotAutoselectSubmodules = false;
881 bool m_bNoAutoselectMissing = false;
882 bool m_bEnableDblClick = true;
883 std::map<CString, CString> m_restorepaths;
884 mutable CReaderWriterLock m_guard;
886 CFont m_uiFont;
888 HMENU m_hShellMenu = nullptr;
889 LPCONTEXTMENU m_pContextMenu = nullptr;
891 void StoreScrollPos();
893 private:
894 void RestoreScrollPos();
895 struct ScrollPos
897 bool enabled = false;
898 int selMark = -1;
899 int nSelectedEntry = -1;
900 POINT coordOrigin{0, 0};
901 } m_sScrollPos;
903 void GitStageEntry(CTGitPath* entry);
904 void GitUnstageEntry(CTGitPath* entry);
905 bool m_bThreeStateCheckboxes = false;
907 public:
908 void UpdateSelectedFileStagingStatus(CTGitPath::StagingStatus newStatus);
911 class CGitStatusListCtrlDropTarget : public CIDropTarget
913 public:
914 CGitStatusListCtrlDropTarget(CGitStatusListCtrl* pGitStatusListCtrl) : CIDropTarget(pGitStatusListCtrl->m_hWnd) { m_pGitStatusListCtrl = pGitStatusListCtrl; }
916 bool OnDrop(FORMATETC* pFmtEtc, STGMEDIUM& medium, DWORD* pdwEffect, POINTL pt) override;
917 HRESULT STDMETHODCALLTYPE DragOver(DWORD grfKeyState, POINTL pt, DWORD __RPC_FAR* pdwEffect) override;
918 private:
919 CGitStatusListCtrl* m_pGitStatusListCtrl = nullptr;
922 class ScopedInDecrement
924 public:
925 ScopedInDecrement(volatile LONG& counter) : m_counter(counter) { InterlockedIncrement(&m_counter); }
926 ~ScopedInDecrement() { InterlockedDecrement(&m_counter); }
928 ScopedInDecrement(const ScopedInDecrement&) = delete;
929 void operator=(const ScopedInDecrement&) = delete;
931 private:
932 volatile LONG& m_counter;