1
// TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2008-2018 - 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.
22 #include "GitStatus.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_NUMCOLUMNS 8
43 //#define SVNSLC_COLURL 0x000000200
44 //#define SVNSLC_COLCOPYFROM 0x000020000
46 #define GITSLC_SHOWUNVERSIONED CTGitPath::LOGACTIONS_UNVER
47 #define GITSLC_SHOWNORMAL 0x00000000
48 #define GITSLC_SHOWMODIFIED (CTGitPath::LOGACTIONS_MODIFIED)
49 #define GITSLC_SHOWADDED (CTGitPath::LOGACTIONS_ADDED|CTGitPath::LOGACTIONS_COPY)
50 #define GITSLC_SHOWREMOVED CTGitPath::LOGACTIONS_DELETED
51 #define GITSLC_SHOWCONFLICTED CTGitPath::LOGACTIONS_UNMERGED
52 #define GITSLC_SHOWMISSING 0x00000000
53 #define GITSLC_SHOWREPLACED CTGitPath::LOGACTIONS_REPLACED
54 #define GITSLC_SHOWMERGED CTGitPath::LOGACTIONS_MERGED
55 #define GITSLC_SHOWIGNORED CTGitPath::LOGACTIONS_IGNORE
56 #define GITSLC_SHOWOBSTRUCTED 0x00000000
57 #define GITSLC_SHOWEXTERNAL 0x00000000
58 #define GITSLC_SHOWINCOMPLETE 0x00000000
59 #define GITSLC_SHOWINEXTERNALS 0x00000000
60 #define GITSLC_SHOWREMOVEDANDPRESENT 0x00000000
61 #define GITSLC_SHOWDIRECTFILES 0x04000000
62 #define GITSLC_SHOWDIRECTFOLDER 0x00000000
63 #define GITSLC_SHOWEXTERNALFROMDIFFERENTREPO 0x00000000
64 #define GITSLC_SHOWSWITCHED 0x00000000
65 #define GITSLC_SHOWINCHANGELIST 0x00000000
66 #define GITSLC_SHOWASSUMEVALID CTGitPath::LOGACTIONS_ASSUMEVALID
67 #define GITSLC_SHOWSKIPWORKTREE CTGitPath::LOGACTIONS_SKIPWORKTREE
69 #define GITSLC_SHOWDIRECTS (GITSLC_SHOWDIRECTFILES | GITSLC_SHOWDIRECTFOLDER)
71 #define GITSLC_SHOWFILES 0x01000000
72 #define GITSLC_SHOWSUBMODULES 0x02000000
73 #define GITSLC_SHOWEVERYTHING 0xffffffff
75 #define GITSLC_SHOWVERSIONED (GITSLC_SHOWNORMAL|GITSLC_SHOWMODIFIED|\
76 GITSLC_SHOWADDED|GITSLC_SHOWREMOVED|GITSLC_SHOWCONFLICTED|GITSLC_SHOWMISSING|\
77 GITSLC_SHOWREPLACED|GITSLC_SHOWMERGED|GITSLC_SHOWIGNORED|GITSLC_SHOWOBSTRUCTED|\
78 GITSLC_SHOWEXTERNAL|GITSLC_SHOWINCOMPLETE|GITSLC_SHOWINEXTERNALS|\
79 GITSLC_SHOWEXTERNALFROMDIFFERENTREPO)
81 #define GITSLC_SHOWVERSIONEDBUTNORMAL (GITSLC_SHOWMODIFIED|GITSLC_SHOWADDED|\
82 GITSLC_SHOWREMOVED|GITSLC_SHOWCONFLICTED|GITSLC_SHOWMISSING|\
83 GITSLC_SHOWREPLACED|GITSLC_SHOWMERGED|GITSLC_SHOWIGNORED|GITSLC_SHOWOBSTRUCTED|\
84 GITSLC_SHOWEXTERNAL|GITSLC_SHOWINCOMPLETE|GITSLC_SHOWINEXTERNALS|\
85 GITSLC_SHOWEXTERNALFROMDIFFERENTREPO)
87 #define GITSLC_SHOWVERSIONEDBUTNORMALANDEXTERNALSFROMDIFFERENTREPOS (GITSLC_SHOWMODIFIED|\
88 GITSLC_SHOWADDED|GITSLC_SHOWREMOVED|GITSLC_SHOWCONFLICTED|GITSLC_SHOWMISSING|\
89 GITSLC_SHOWREPLACED|GITSLC_SHOWMERGED|GITSLC_SHOWIGNORED|GITSLC_SHOWOBSTRUCTED|\
90 GITSLC_SHOWINCOMPLETE|GITSLC_SHOWEXTERNAL|GITSLC_SHOWINEXTERNALS)
92 #define GITSLC_SHOWVERSIONEDBUTNORMALANDEXTERNALS (GITSLC_SHOWMODIFIED|\
93 GITSLC_SHOWADDED|GITSLC_SHOWREMOVED|GITSLC_SHOWCONFLICTED|GITSLC_SHOWMISSING|\
94 GITSLC_SHOWREPLACED|GITSLC_SHOWMERGED|GITSLC_SHOWIGNORED|GITSLC_SHOWOBSTRUCTED|\
95 GITSLC_SHOWINCOMPLETE)
97 #define GITSLC_SHOWALL (GITSLC_SHOWVERSIONED|GITSLC_SHOWUNVERSIONED)
99 #define GITSLC_POPALL 0xFFFFFFFFFFFFFFFF
100 #define GITSLC_POPCOMPAREWITHBASE CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_COMPARE)
101 #define GITSLC_POPCOMPARE CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_COMPAREWC)
102 #define GITSLC_POPGNUDIFF CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_GNUDIFF1)
103 #define GITSLC_POPREVERT CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_REVERT)
104 #define GITSLC_POPSHOWLOG CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_LOG)
105 #define GITSLC_POPSHOWLOGSUBMODULE CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_LOGSUBMODULE)
106 #define GITSLC_POPSHOWLOGOLDNAME CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_LOGOLDNAME)
107 #define GITSLC_POPOPEN CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_OPEN)
108 #define GITSLC_POPDELETE CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_DELETE)
109 #define GITSLC_POPADD CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_ADD)
110 #define GITSLC_POPIGNORE CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_IGNORE)
111 #define GITSLC_POPCONFLICT CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_EDITCONFLICT)
112 #define GITSLC_POPRESOLVE CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_RESOLVECONFLICT)
113 #define GITSLC_POPEXPLORE CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_EXPLORE)
114 #define GITSLC_POPCOMMIT CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_COMMIT)
115 #define GITSLC_POPCHANGELISTS CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_CHECKGROUP)
116 #define GITSLC_POPBLAME CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_BLAME)
117 #define GITSLC_POPSAVEAS CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_SAVEAS)
118 #define GITSLC_POPCOMPARETWOFILES CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_COMPARETWOFILES)
119 #define GITSLC_POPRESTORE CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_POPRESTORE)
120 #define GITSLC_POPASSUMEVALID CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_ASSUMEVALID)
121 #define GITSLC_POPSKIPWORKTREE CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_SKIPWORKTREE)
122 #define GITSLC_POPEXPORT CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_EXPORT)
123 #define GITSLC_POPUNSETIGNORELOCALCHANGES CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_UNSETIGNORELOCALCHANGES)
124 #define GITSLC_POPPREPAREDIFF CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_PREPAREDIFF)
126 #define GITSLC_IGNORECHANGELIST L"ignore-on-commit"
128 #define OVL_RESTORE 1
130 typedef int (__cdecl
*GENERICCOMPAREFN
)(const void * elem1
, const void * elem2
);
132 class CGitStatusListCtrlDropTarget
;
135 * \ingroup TortoiseProc
136 * Simple utility class that defines the sort column order.
142 CSorter ( ColumnManager
* columnManager
146 bool operator() ( const CTGitPath
* entry1
147 , const CTGitPath
* entry2
) const;
149 static int A2L(const CString
&str
)
159 ColumnManager
* columnManager
;
167 * A List control, based on the MFC CListCtrl which shows a list of
168 * files with their git status. The control also provides a context
169 * menu to do some git tasks on the selected files.
171 * This is the main control used in many dialogs to show a list of files to
174 class CGitStatusListCtrl
:
175 public CResizableColumnsListCtrl
<CListCtrl
>
181 /** Compare with base version. when current version is zero (i.e. working tree changes), compare working tree and HEAD */
186 /** Compare with base version and generate unified diff. when current version is zero (i.e. working tree changes), compare working tree and HEAD */
190 IDGITLC_LOGSUBMODULE
,
191 IDGITLC_EDITCONFLICT
,
193 IDGITLC_IGNOREFOLDER
,
195 IDGITLC_RESOLVECONFLICT
,
198 IDGITLC_RESOLVETHEIRS
,
199 IDGITLC_RESOLVEMINE
,
202 IDGITLC_COPYRELPATHS
,
204 IDGITLC_REMOVEFROMCS
,
206 IDGITLC_CREATEIGNORECS
,
208 IDGITLC_UNCHECKGROUP
,
209 /** Compare current version and working tree */
213 IDGITLC_REVERTTOREV
,
214 IDGITLC_REVERTTOPARENT
,
217 /** used in sync dlg, compare in/out file changes; in combination with m_Rev1 and m_Rev2 */
218 IDGITLC_COMPARETWOREVISIONS
,
219 /** used in sync dlg, compare in/out file changes; in combination with m_Rev1 and m_Rev2 */
220 IDGITLC_GNUDIFF2REVISIONS
,
221 /** Compare two selected files */
222 IDGITLC_COMPARETWOFILES
,
224 IDGITLC_CREATERESTORE
,
225 IDGITLC_RESTOREPATH
,
226 IDGITLC_ASSUMEVALID
,
227 IDGITLC_SKIPWORKTREE
,
229 IDGITLC_UNSETIGNORELOCALCHANGES
,
230 IDGITLC_PREPAREDIFF
,
231 IDGITLC_PREPAREDIFF_COMPARE
,
234 IDGITLC_COPYFILENAMES
,
237 // the IDSVNLC_MOVETOCS *must* be the last index, because it contains a dynamic submenu where
238 // the submenu items get command ID's sequent to this number
241 static_assert(IDGITLC_MOVETOCS
< 64, "IDs must be <64 in order to be usable in a bitfield");
242 int GetColumnIndex(int colmask
);
243 static inline unsigned __int64
GetContextMenuBit(int i
){ return ((unsigned __int64
)0x1)<<i
;}
245 * Sent to the parent window (using ::SendMessage) after a context menu
246 * command has finished if the item count has changed.
248 static const UINT GITSLNM_ITEMCOUNTCHANGED
;
250 * Sent to the parent window (using ::SendMessage) when the control needs
251 * to be refreshed. Since this is done usually in the parent window using
252 * a thread, this message is used to tell the parent to do exactly that.
254 static const UINT GITSLNM_NEEDSREFRESH
;
257 * Sent to the parent window (using ::SendMessage) when the user drops
258 * files on the control. The LPARAM is a pointer to a TCHAR string
259 * containing the dropped path.
261 static const UINT GITSLNM_ADDFILE
;
264 * Sent to the parent window (using ::SendMessage) when the user checks/unchecks
265 * one or more items in the control. The WPARAM contains the number of
266 * checked items in the control.
268 static const UINT GITSLNM_CHECKCHANGED
;
270 static const UINT GITSLNM_ITEMCHANGED
;
272 CGitStatusListCtrl(void);
273 ~CGitStatusListCtrl(void);
275 HWND
GetParentHWND();
281 * \ingroup TortoiseProc
282 * Helper class for CGitStatusListCtrl which represents
283 * the data for each file shown.
289 FileEntry() : status(git_wc_status_unversioned
)
290 // , copyfrom_rev(GIT_REV_ZERO)
291 , last_commit_date(0)
292 , last_commit_rev(GIT_REV_ZERO
)
293 // , remoterev(GIT_REV_ZERO)
294 , textstatus(git_wc_status_unversioned
)
295 , propstatus(git_wc_status_unversioned
)
296 // , remotestatus(git_wc_status_unversioned)
297 // , remotetextstatus(git_wc_status_unversioned)
298 // , remotepropstatus(git_wc_status_unversioned)
302 , inunversionedfolder(false)
304 , differentrepo(false)
308 , Revision(GIT_REV_ZERO
)
309 , isConflicted(false)
311 /// , working_size(SVN_WC_ENTRY_WORKING_SIZE_UNKNOWN)
312 // , depth(git_depth_unknown)
315 const CTGitPath
& GetPath() const
319 const bool IsChecked() const
323 CString
GetRelativeGitPath() const
325 if (path
.IsEquivalentTo(basepath
))
326 return path
.GetGitPathString();
327 return path
.GetGitPathString().Mid(basepath
.GetGitPathString().GetLength()+1);
329 const bool IsFolder() const
333 const bool IsInExternal() const
337 const bool IsNested() const
341 const bool IsFromDifferentRepository() const
343 return differentrepo
;
345 CString
GetDisplayName() const
347 CString
const& chopped
= path
.GetDisplayString(&basepath
);
348 if (!chopped
.IsEmpty())
354 // "Display name" must not be empty.
355 return path
.GetFileOrDirectoryName();
358 CString
GetChangeList() const
362 // CString GetURL() const
367 git_wc_status_kind status
; ///< local status
368 git_wc_status_kind textstatus
; ///< local text status
369 git_wc_status_kind propstatus
; ///< local property status
372 CTGitPath path
; ///< full path of the file
373 CTGitPath basepath
; ///< common ancestor path of all files
375 CString changelist
; ///< the name of the changelist the item belongs to
377 CString last_commit_author
; ///< the author which last committed this item
378 CTime last_commit_date
; ///< the date when this item was last committed
379 git_revnum_t last_commit_rev
; ///< the revision where this item was last committed
381 git_revnum_t remoterev
; ///< the revision in HEAD of the repository
382 bool copied
; ///< if the file/folder is added-with-history
383 bool switched
; ///< if the file/folder is switched to another url
384 bool checked
; ///< if the file is checked in the list control
385 bool inunversionedfolder
; ///< if the file is inside an unversioned folder
386 bool inexternal
; ///< if the item is in an external folder
387 bool differentrepo
; ///< if the item is from a different repository than the rest
388 bool direct
; ///< directly included (TRUE) or just a child of a folder
389 bool isfolder
; ///< TRUE if entry refers to a folder
390 bool isNested
; ///< TRUE if the folder from a different repository and/or path
391 bool isConflicted
; ///< TRUE if a file entry is conflicted, i.e. if it has the conflicted paths set
392 git_revnum_t Revision
; ///< the base revision
393 // PropertyList present_props; ///< cacheable properties present in BASE
394 git_depth_t depth
; ///< the depth of this entry
395 friend class CGitStatusListCtrl
;
396 friend class CGitStatusListCtrlDropTarget
;
397 friend class CSorter
;
402 * Initializes the control, sets up the columns.
403 * \param dwColumns mask of columns to show. Use the GitSLC_COLxxx defines.
404 * \param sColumnInfoContainer Name of a registry key
405 * where the position and visibility of each column
406 * is saved and used from. If the registry key
407 * doesn't exist, the default order is used
408 * and dwColumns tells which columns are visible.
409 * \param dwContextMenus mask of context menus to be active, not all make sense for every use of this control.
410 * Use the GitSLC_POPxxx defines.
411 * \param bHasCheckboxes TRUE if the control should show check boxes on the left of each file entry.
412 * \param bHasWC TRUE if the reporisty is not a bare repository (hides wc related items on the contextmenu)
414 void Init(DWORD dwColumns
, const CString
& sColumnInfoContainer
, unsigned __int64 dwContextMenus
= ((GITSLC_POPALL
^ GITSLC_POPCOMMIT
) ^ GITSLC_POPRESTORE
), bool bHasCheckboxes
= true, bool bHasWC
= true, DWORD allowedColumns
= 0xffffffff);
416 * Sets a background image for the list control.
417 * The image is shown in the right bottom corner.
418 * \param nID the resource ID of the bitmap to use as the background
420 bool SetBackgroundImage(UINT nID
);
422 UINT m_nBackgroundImageID
;
425 * Makes the 'ignore' context menu only ignore the files and not add the
426 * folder which gets the Git:ignore property changed to the list.
427 * This is needed e.g. for the Add-dialog, where the modified folder
428 * showing up would break the resulting "add" command.
430 void SetIgnoreRemoveOnly(bool bRemoveOnly
= true) {m_bIgnoreRemoveOnly
= bRemoveOnly
;}
432 * The unversioned items are by default shown after all other files in the list.
433 * If that behavior should be changed, set this value to false.
435 void PutUnversionedLast(bool bLast
) {m_bUnversionedLast
= bLast
;}
437 * Fetches the git status of all files and stores the information
438 * about them in an internal array.
439 * \param sFilePath path to a file which contains a list of files and/or folders for which to
440 * fetch the status, separated by newlines.
441 * \param bUpdate TRUE if the remote status is requested too.
442 * \return TRUE on success.
444 BOOL
GetStatus (const CTGitPathList
* pathList
= nullptr
445 , bool bUpdate
= false
446 , bool bShowIgnores
= false
447 , bool bShowUnRev
= false
448 , bool bShowLocalChangesIgnored
= false);
451 * Populates the list control with the previously (with GetStatus) gathered status information.
452 * \param dwShow mask of file types to show. Use the GitSLC_SHOWxxx defines.
453 * \param dwCheck mask of file types to check. Use GitLC_SHOWxxx defines. Default (0) means 'use the entry's stored check status'
455 void Show(unsigned int dwShow
, unsigned int dwCheck
= 0, bool bShowFolders
= true,BOOL updateStatusList
=FALSE
, bool UseStoredCheckStatus
=false);
458 * Copies the selected entries in the control to the clipboard. The entries
459 * are separated by newlines.
460 * \param dwCols the columns to copy. Each column is separated by a tab.
462 bool CopySelectedEntriesToClipboard(DWORD dwCols
, int cmd
);
465 * If during the call to GetStatus() some Git:externals are found from different
466 * repositories than the first one checked, then this method returns TRUE.
468 BOOL
HasExternalsFromDifferentRepos() const {return m_bHasExternalsFromDifferentRepos
;}
471 * If during the call to GetStatus() some Git:externals are found then this method returns TRUE.
473 BOOL
HasExternals() const {return m_bHasExternals
;}
476 * If unversioned files are found (but not necessarily shown) TRUE is returned.
478 BOOL
HasUnversionedItems() {return m_bHasUnversionedItems
;}
481 * If there are any change lists defined in the working copy, TRUE is returned
483 BOOL
HasChangeLists() const {return m_bHasChangeLists
;}
486 * Returns the file entry data for the list control index.
488 CTGitPath
* GetListEntry(int index
);
491 * Returns the file entry data for the specified path.
492 * \note The entry might not be shown in the list control.
494 //CGitStatusListCtrl::FileEntry * GetListEntry(const CTGitPath& path);
497 * Returns the file entry data for the specified path in the list control.
499 //CGitStatusListCtrl::FileEntry * GetVisibleListEntry(const CTGitPath& path);
502 * Returns a String containing some statistics like number of modified, normal, deleted,...
505 CString
GetStatisticsString(bool simple
=false);
508 * Set a static control which will be updated automatically with
509 * the number of selected and total files shown in the list control.
511 void SetStatLabel(CWnd
* pStatLabel
){m_pStatLabel
= pStatLabel
;};
514 * Set a tri-state checkbox which is updated automatically if the
515 * user checks/unchecks file entries in the list control to indicate
516 * if all files are checked, none are checked or some are checked.
518 void SetSelectButton(CButton
* pButton
) {m_pSelectButton
= pButton
;}
521 * Set a button which is de-/activated automatically. The button is
522 * only set active if at least one item is selected.
524 void SetConfirmButton(CButton
* pButton
) {m_pConfirmButton
= pButton
;}
527 * Select/unselect all entries in the list control.
528 * \param bSelect TRUE to check, FALSE to uncheck.
530 void SelectAll(bool bSelect
, bool bIncludeNoCommits
= false);
533 * Checks or unchecks all specified items
534 * \param dwCheck GITLC_SHOWxxx defines
535 * \param check if true matching items will be selected, false unchecks matching items
537 void Check(DWORD dwCheck
, bool check
= true);
539 /** Set a checkbox on an entry in the listbox
540 * Keeps the listctrl checked state and the FileEntry's checked flag in sync
542 void SetEntryCheck(CTGitPath
* pEntry
, int listboxIndex
, bool bCheck
);
544 void ResetChecked(const CTGitPath
& entry
);
546 /** Write a list of the checked items' paths into a path list
548 void WriteCheckedNamesToPathList(CTGitPathList
& pathList
);
551 * Returns the parent directory of all entries in the control.
552 * if \a bStrict is set to false, then the paths passed to the control
553 * to fetch the status (in GetStatus()) are used if possible.
555 CString
GetCommonDirectory(bool bStrict
);
558 * Sets a pointer to a boolean variable which is checked periodically
559 * during the status fetching. As soon as the variable changes to true,
560 * the operations stops.
562 void SetCancelBool(bool * pbCanceled
) {m_pbCanceled
= pbCanceled
;}
565 * Sets the string shown in the control while the status is fetched.
566 * If not set, it defaults to "please wait..."
568 void SetBusyString(const CString
& str
) {m_sBusy
= str
;}
569 void SetBusyString(UINT id
) {m_sBusy
.LoadString(id
);}
572 * Sets the string shown in the control if no items are shown. This
573 * can happen for example if there's nothing modified and the unversioned
574 * files aren't shown either, so there's nothing to commit.
575 * If not set, it defaults to "file list is empty".
577 void SetEmptyString(const CString
& str
) {m_sEmpty
= str
;}
578 void SetEmptyString(UINT id
) {m_sEmpty
.LoadString(id
);}
581 * Returns the number of selected items
583 LONG
GetSelected(){return m_nSelected
;};
586 * Enables dropping of files on the control.
588 bool EnableFileDrop();
591 * Checks if the path already exists in the list.
593 bool HasPath(const CTGitPath
& path
);
596 * Forces the children to be checked when the parent folder is checked,
597 * and the parent folder to be unchecked if one of its children is unchecked.
599 void CheckChildrenWithParent(bool bCheck
) {m_bCheckChildrenWithParent
= bCheck
;}
602 * Allows checking the items if change lists are present. If set to false,
603 * items are not checked if at least one changelist is available.
605 void CheckIfChangelistsArePresent(bool bCheck
) {m_bCheckIfGroupsExist
= bCheck
;}
607 * Returns the currently used show flags passed to the Show() method.
609 DWORD
GetShowFlags() {return m_dwShow
;}
612 CString
GetLastErrorMessage() {return m_sLastError
;}
614 void BusyCursor(bool bBusy
) { m_bWaitCursor
= bBusy
; }
616 LONG
GetUnversionedCount() { return m_nShownUnversioned
; }
617 LONG
GetModifiedCount() { return m_nShownModified
; }
618 LONG
GetAddedCount() { return m_nShownAdded
; }
619 LONG
GetDeletedCount() { return m_nShownDeleted
; }
620 LONG
GetConflictedCount() { return m_nShownConflicted
; }
621 LONG
GetFileCount() { return m_nShownFiles
; }
622 LONG
GetSubmoduleCount() { return m_nShownSubmodules
; }
624 CAutoReadLock
AcquireReadLock() { return CAutoReadLock(m_guard
); }
625 CAutoReadWeakLock
AcquireReadWeakLock(DWORD timeout
) { return CAutoReadWeakLock(m_guard
, timeout
); }
627 LONG m_nTargetCount
; ///< number of targets in the file passed to GetStatus()
629 CString m_sURL
; ///< the URL of the target or "(multiple targets)"
631 bool m_amend
; ///< if true show the changes to the revision before the last commit
633 bool m_bIncludedStaged
;
635 CString m_sUUID
; ///< the UUID of the associated repository
637 CString m_sDisplayedBranch
; ///< When on LogDialog, what is the current displayed branch
639 CWnd
*m_hwndLogicalParent
;
641 DECLARE_MESSAGE_MAP()
644 void SetBusy(bool b
) {m_bBusy
= b
; Invalidate();}
645 bool IsBusy() const { return m_bBusy
; }
646 void SetHasCheckboxes(bool bHasCheckboxes
)
648 m_bHasCheckboxes
= bHasCheckboxes
;
649 DWORD exStyle
= GetExtendedStyle();
651 exStyle
|= LVS_EX_CHECKBOXES
;
653 exStyle
&= ~LVS_EX_CHECKBOXES
;
654 SetExtendedStyle(exStyle
);
658 CString
GetCellText(int listIndex
, int column
); ///< get the text for a certain grid cell
659 //void AddEntry(FileEntry * entry, WORD langID, int listIndex); ///< add an entry to the control
660 void RemoveListEntry(int index
); ///< removes an entry from the listcontrol and both arrays
661 void BuildStatistics(); ///< build the statistics and correct the case of files/folders
662 void StartDiff(int fileindex
); ///< start the external diff program
663 void StartDiffWC(int fileindex
); ///< start the external diff program
664 void StartDiffTwo(int fileindex
);
666 void SetGitIndexFlagsForSelectedFiles(UINT message
, BOOL assumevalid
, BOOL skipworktree
);
668 CString m_sMarkForDiffFilename
;
669 CString m_sMarkForDiffVersion
;
671 /* while rebasing, Their and My versios are swapped. */
672 bool m_bIsRevertTheirMy
;
680 void OpenFile(CTGitPath
*path
,int mode
);
682 /// Clear the status vector (contains custodial pointers)
683 void ClearStatusArray();
685 /// Sort predicate function - Compare the paths of two entries without regard to case
686 //static bool EntryPathCompareNoCase(const FileEntry* pEntry1, const FileEntry* pEntry2);
688 /// Predicate used to build a list of only the versioned entries of the FileEntry array
689 //static bool IsEntryVersioned(const FileEntry* pEntry1);
691 /// Look up the relevant show flags for a particular Git status value
692 DWORD
GetShowFlagsFromGitStatus(git_wc_status_kind status
);
694 /// Adjust the checkbox-state on all descendants of a specific item
695 //void SetCheckOnAllDescendentsOf(const FileEntry* parentEntry, bool bCheck);
697 /// Build a path list of all the selected items in the list (NOTE - SELECTED, not CHECKED)
698 void FillListOfSelectedItemPaths(CTGitPathList
& pathList
, bool bNoIgnored
= false);
700 /// Enables/Disables group view and adds all groups to the list control.
701 /// If bForce is true, then group view is enabled and the 'null' group is added.
702 bool PrepareGroups(bool bForce
= false);
703 /// Returns the group number to which the group header belongs
704 /// If the point is not over a group header, -1 is returned
705 int GetGroupFromPoint(POINT
* ppt
);
706 /// Returns the number of change lists the selection has
707 size_t GetNumberOfChangelistsInSelection();
709 /// Puts the item to the corresponding group
710 bool SetItemGroup(int item
, int groupindex
);
712 void CheckEntry(int index
, int nListItems
);
713 void UncheckEntry(int index
, int nListItems
);
715 /// sends an GitSLNM_CHECKCHANGED notification to the parent
717 CWnd
* GetLogicalParent() { return m_hwndLogicalParent
? m_hwndLogicalParent
: this->GetParent(); }
719 void OnContextMenuList(CWnd
* pWnd
, CPoint point
);
720 void OnContextMenuGroup(CWnd
* pWnd
, CPoint point
);
721 bool CheckMultipleDiffs();
723 void DeleteSelectedFiles();
725 virtual void PreSubclassWindow() override
;
726 virtual BOOL
PreTranslateMessage(MSG
* pMsg
) override
;
727 virtual BOOL
OnWndMsg(UINT message
, WPARAM wParam
, LPARAM lParam
, LRESULT
* pResult
) override
;
728 virtual ULONG
GetGestureStatus(CPoint ptTouch
) override
;
729 afx_msg
void OnSysColorChange();
730 afx_msg
void OnBeginDrag(NMHDR
* pNMHDR
, LRESULT
* pResult
);
731 afx_msg
void OnHdnItemclick(NMHDR
*pNMHDR
, LRESULT
*pResult
);
732 afx_msg BOOL
OnLvnItemchanged(NMHDR
*pNMHDR
, LRESULT
*pResult
);
733 afx_msg
void OnContextMenu(CWnd
* pWnd
, CPoint point
);
735 afx_msg
void OnNMDblclk(NMHDR
*pNMHDR
, LRESULT
*pResult
);
736 afx_msg
void OnLvnGetInfoTip(NMHDR
*pNMHDR
, LRESULT
*pResult
);
737 afx_msg BOOL
OnNMCustomdraw(NMHDR
* pNMHDR
, LRESULT
* pResult
);
738 afx_msg
void OnLvnGetdispinfo(NMHDR
* pNMHDR
, LRESULT
* pResult
);
739 afx_msg BOOL
OnSetCursor(CWnd
* pWnd
, UINT nHitTest
, UINT message
);
740 afx_msg UINT
OnGetDlgCode();
741 afx_msg
void OnNMReturn(NMHDR
*pNMHDR
, LRESULT
*pResult
);
742 afx_msg
void OnKeyDown(UINT nChar
, UINT nRepCnt
, UINT nFlags
);
743 afx_msg
void OnPaint();
746 void FileSaveAs(CTGitPath
*path
);
747 int RevertSelectedItemToVersion(bool parent
= false);
751 bool m_bAscending
; ///< sort direction
752 int m_nSortedColumn
; ///< which column to sort
753 bool m_bHasCheckboxes
;
755 bool m_bUnversionedLast
;
756 bool m_bHasExternalsFromDifferentRepos
;
757 bool m_bHasExternals
;
758 BOOL m_bHasUnversionedItems
;
759 bool m_bHasChangeLists
;
760 //typedef std::vector<FileEntry*> FileEntryVector;
761 //FileEntryVector m_arStatusArray;
762 std::vector
<const CTGitPath
*> m_arStatusArray
;
763 std::vector
<size_t> m_arListArray
;
764 std::map
<CString
, int> m_changelists
;
765 bool m_bHasIgnoreGroup
;
766 CTGitPathList m_StatusFileList
;
767 CTGitPathList m_UnRevFileList
;
768 CTGitPathList m_IgnoreFileList
;
769 CTGitPathList m_LocalChangesIgnoredFileList
; // assume valid & skip worktree
770 CString m_sLastError
;
784 LONG m_nShownUnversioned
;
785 LONG m_nShownModified
;
787 LONG m_nShownDeleted
;
788 LONG m_nShownConflicted
;
790 LONG m_nShownSubmodules
;
792 DWORD m_dwDefaultColumns
;
797 unsigned __int64 m_dwContextMenus
;
801 bool m_bIgnoreRemoveOnly
;
802 bool m_bCheckIfGroupsExist
;
803 bool m_bFileDropsEnabled
;
810 CButton
* m_pSelectButton
;
811 CButton
* m_pConfirmButton
;
817 bool m_bCheckChildrenWithParent
;
818 std::unique_ptr
<CGitStatusListCtrlDropTarget
> m_pDropTarget
;
819 volatile LONG m_nBlockItemChangeHandler
;
820 std::map
<CString
,bool> m_mapFilenameToChecked
; ///< Remember de-/selected items
821 std::set
<CString
> m_setDirectFiles
;
822 CComCriticalSection m_critSec
;
824 friend class CGitStatusListCtrlDropTarget
;
828 FILELIST_MODIFY
= 0x1,
829 FILELIST_UNVER
= 0x2,
830 FILELIST_IGNORE
=0x4,
831 FILELIST_LOCALCHANGESIGNORED
= 0x8, // assume valid & skip worktree files
834 int UpdateFileList(const CTGitPathList
* list
= nullptr);
836 int UpdateFileList(int mask
, bool once
= true, const CTGitPathList
* list
= nullptr);
837 int UpdateUnRevFileList(CTGitPathList
&list
);
838 int UpdateUnRevFileList(const CTGitPathList
* list
= nullptr);
839 int UpdateIgnoreFileList(const CTGitPathList
* list
= nullptr);
840 int UpdateLocalChangesIgnoredFileList(const CTGitPathList
* list
= nullptr);
842 int UpdateWithGitPathList(CTGitPathList
&list
);
844 void AddEntry(size_t arStatusArrayIndex
, CTGitPath
* path
, WORD langID
, int ListIndex
);
847 CGitHash m_CurrentVersion
;
848 bool m_bDoNotAutoselectSubmodules
;
849 bool m_bNoAutoselectMissing
;
850 std::map
<CString
, CString
> m_restorepaths
;
851 mutable CReaderWriterLock m_guard
;
856 LPCONTEXTMENU m_pContextMenu
;
858 void StoreScrollPos();
861 void RestoreScrollPos();
864 bool enabled
= false;
871 class CGitStatusListCtrlDropTarget
: public CIDropTarget
874 CGitStatusListCtrlDropTarget(CGitStatusListCtrl
* pGitStatusListCtrl
) : CIDropTarget(pGitStatusListCtrl
->m_hWnd
) { m_pGitStatusListCtrl
= pGitStatusListCtrl
; }
876 virtual bool OnDrop(FORMATETC
* pFmtEtc
, STGMEDIUM
& medium
, DWORD
* pdwEffect
, POINTL pt
) override
;
877 virtual HRESULT STDMETHODCALLTYPE
DragOver(DWORD grfKeyState
, POINTL pt
, DWORD __RPC_FAR
* pdwEffect
) override
;
879 CGitStatusListCtrl
* m_pGitStatusListCtrl
;
882 class ScopedInDecrement
885 ScopedInDecrement(volatile LONG
& counter
) : m_counter(counter
) { InterlockedIncrement(&m_counter
); }
886 ~ScopedInDecrement() { InterlockedDecrement(&m_counter
); }
888 ScopedInDecrement(const ScopedInDecrement
&) = delete;
889 void operator=(const ScopedInDecrement
&) = delete;
892 volatile LONG
& m_counter
;