1 // TortoiseSVN - a Windows shell extension for easy version control
3 // Copyright (C) 2003-2008 - TortoiseSVN
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software Foundation,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 #include "GitStatus.h"
23 #include "GitConfig.h"
26 #include "CommonResource.h"
27 #include "HintListCtrl.h"
29 #define SVN_WC_ENTRY_WORKING_SIZE_UNKNOWN (-1)
31 // these defines must be in the order the columns are inserted!
32 #define SVNSLC_COLFILENAME 0x000000002
33 #define SVNSLC_COLEXT 0x000000004
34 #define SVNSLC_COLSTATUS 0x000000008
35 //#define SVNSLC_COLTEXTSTATUS 0x000000010
36 //#define SVNSLC_COLPROPSTATUS 0x000000020
37 //#define SVNSLC_COLAUTHOR 0x000000040
38 //#define SVNSLC_COLREVISION 0x000000080
39 //#define SVNSLC_COLDATE 0x000000100
40 //#define SVNSLC_COLMODIFICATIONDATE 0x000000200
41 #define SVNSLC_COLADD 0x000000010
42 #define SVNSLC_COLDEL 0x000000020
43 #define SVNSLC_NUMCOLUMNS 6
45 //#define SVNSLC_COLREMOTESTATUS 0x000000010
46 //#define SVNSLC_COLREMOTETEXT 0x000000080
47 //#define SVNSLC_COLREMOTEPROP 0x000000100
48 //#define SVNSLC_COLURL 0x000000200
49 //#define SVNSLC_COLLOCK 0x000000400
50 //#define SVNSLC_COLLOCKCOMMENT 0x000000800
52 //#define SVNSLC_COLREMOTEREVISION 0x000004000
54 //#define SVNSLC_COLSVNNEEDSLOCK 0x000010000
55 //#define SVNSLC_COLCOPYFROM 0x000020000
58 #define SVNSLC_SHOWUNVERSIONED CTGitPath::LOGACTIONS_UNVER
59 #define SVNSLC_SHOWNORMAL 0x000000000
60 #define SVNSLC_SHOWMODIFIED (CTGitPath::LOGACTIONS_MODIFIED)
61 #define SVNSLC_SHOWADDED (CTGitPath::LOGACTIONS_ADDED|CTGitPath::LOGACTIONS_COPY)
62 #define SVNSLC_SHOWREMOVED CTGitPath::LOGACTIONS_DELETED
63 #define SVNSLC_SHOWCONFLICTED CTGitPath::LOGACTIONS_UNMERGED
64 #define SVNSLC_SHOWMISSING 0x00000000
65 #define SVNSLC_SHOWREPLACED CTGitPath::LOGACTIONS_REPLACED
66 #define SVNSLC_SHOWMERGED CTGitPath::LOGACTIONS_MERGED
67 #define SVNSLC_SHOWIGNORED CTGitPath::LOGACTIONS_IGNORE
68 #define SVNSLC_SHOWOBSTRUCTED 0x00000000
69 #define SVNSLC_SHOWEXTERNAL 0x00000000
70 #define SVNSLC_SHOWINCOMPLETE 0x00000000
71 #define SVNSLC_SHOWINEXTERNALS 0x00000000
72 #define SVNSLC_SHOWREMOVEDANDPRESENT 0x00000000
73 #define SVNSLC_SHOWLOCKS 0x00000000
74 #define SVNSLC_SHOWDIRECTFILES 0x00000000
75 #define SVNSLC_SHOWDIRECTFOLDER 0x00000000
76 #define SVNSLC_SHOWEXTERNALFROMDIFFERENTREPO 0x00000000
77 #define SVNSLC_SHOWSWITCHED 0x00000000
78 #define SVNSLC_SHOWINCHANGELIST 0x00000000
80 #define SVNSLC_SHOWDIRECTS (SVNSLC_SHOWDIRECTFILES | SVNSLC_SHOWDIRECTFOLDER)
83 #define SVNSLC_SHOWVERSIONED (CTGitPath::LOGACTIONS_FORWORD|SVNSLC_SHOWNORMAL|SVNSLC_SHOWMODIFIED|\
84 SVNSLC_SHOWADDED|SVNSLC_SHOWREMOVED|SVNSLC_SHOWCONFLICTED|SVNSLC_SHOWMISSING|\
85 SVNSLC_SHOWREPLACED|SVNSLC_SHOWMERGED|SVNSLC_SHOWIGNORED|SVNSLC_SHOWOBSTRUCTED|\
86 SVNSLC_SHOWEXTERNAL|SVNSLC_SHOWINCOMPLETE|SVNSLC_SHOWINEXTERNALS|\
87 SVNSLC_SHOWEXTERNALFROMDIFFERENTREPO)
89 #define SVNSLC_SHOWVERSIONEDBUTNORMAL (SVNSLC_SHOWMODIFIED|SVNSLC_SHOWADDED|\
90 SVNSLC_SHOWREMOVED|SVNSLC_SHOWCONFLICTED|SVNSLC_SHOWMISSING|\
91 SVNSLC_SHOWREPLACED|SVNSLC_SHOWMERGED|SVNSLC_SHOWIGNORED|SVNSLC_SHOWOBSTRUCTED|\
92 SVNSLC_SHOWEXTERNAL|SVNSLC_SHOWINCOMPLETE|SVNSLC_SHOWINEXTERNALS|\
93 SVNSLC_SHOWEXTERNALFROMDIFFERENTREPO)
95 #define SVNSLC_SHOWVERSIONEDBUTNORMALANDEXTERNALSFROMDIFFERENTREPOS (SVNSLC_SHOWMODIFIED|\
96 SVNSLC_SHOWADDED|SVNSLC_SHOWREMOVED|SVNSLC_SHOWCONFLICTED|SVNSLC_SHOWMISSING|\
97 SVNSLC_SHOWREPLACED|SVNSLC_SHOWMERGED|SVNSLC_SHOWIGNORED|SVNSLC_SHOWOBSTRUCTED|\
98 SVNSLC_SHOWINCOMPLETE|SVNSLC_SHOWEXTERNAL|SVNSLC_SHOWINEXTERNALS)
100 #define SVNSLC_SHOWVERSIONEDBUTNORMALANDEXTERNALS (SVNSLC_SHOWMODIFIED|\
101 SVNSLC_SHOWADDED|SVNSLC_SHOWREMOVED|SVNSLC_SHOWCONFLICTED|SVNSLC_SHOWMISSING|\
102 SVNSLC_SHOWREPLACED|SVNSLC_SHOWMERGED|SVNSLC_SHOWIGNORED|SVNSLC_SHOWOBSTRUCTED|\
103 SVNSLC_SHOWINCOMPLETE)
105 #define SVNSLC_SHOWALL (SVNSLC_SHOWVERSIONED|SVNSLC_SHOWUNVERSIONED)
107 #define SVNSLC_POPALL 0xFFFFFFFFFFFFFFFF
108 #define SVNSLC_POPCOMPAREWITHBASE CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDSVNLC_COMPARE)
109 #define SVNSLC_POPCOMPARE CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDSVNLC_COMPAREWC)
110 #define SVNSLC_POPGNUDIFF CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDSVNLC_GNUDIFF1)
111 #define SVNSLC_POPREVERT CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDSVNLC_REVERT)
112 #define SVNSLC_POPUPDATE CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDSVNLC_UPDATE)
113 #define SVNSLC_POPSHOWLOG CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDSVNLC_LOG)
114 #define SVNSLC_POPOPEN CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDSVNLC_OPEN)
115 #define SVNSLC_POPDELETE CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDSVNLC_DELETE)
116 #define SVNSLC_POPADD CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDSVNLC_ADD)
117 #define SVNSLC_POPIGNORE CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDSVNLC_IGNORE)
118 #define SVNSLC_POPCONFLICT CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDSVNLC_EDITCONFLICT)
119 #define SVNSLC_POPRESOLVE CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDSVNLC_RESOLVECONFLICT)
120 #define SVNSLC_POPLOCK CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDSVNLC_LOCK)
121 #define SVNSLC_POPUNLOCK CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDSVNLC_UNLOCK)
122 #define SVNSLC_POPUNLOCKFORCE CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDSVNLC_UNLOCKFORCE)
123 #define SVNSLC_POPEXPLORE CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDSVNLC_EXPLORE)
124 #define SVNSLC_POPCOMMIT CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDSVNLC_COMMIT)
125 #define SVNSLC_POPPROPERTIES CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDSVNLC_PROPERTIES)
126 #define SVNSLC_POPREPAIRMOVE CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDSVNLC_REPAIRMOVE)
127 #define SVNSLC_POPCHANGELISTS CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDSVNLC_CHECKGROUP)
128 #define SVNSLC_POPBLAME CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDSVNLC_BLAME)
129 #define SVNSLC_POPSAVEAS CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDSVNLC_SAVEAS)
131 #define SVNSLC_IGNORECHANGELIST _T("ignore-on-commit")
133 // This gives up to 64 standard properties and menu entries
134 // plus 192 user-defined properties (should be plenty).
135 // User-defined properties will start at column SVNSLC_NUMCOLUMNS+1
136 // but in the registry, we will record them starting at SVNSLC_USERPROPCOLOFFSET.
138 #define SVNSLC_USERPROPCOLOFFSET 0x40
139 #define SVNSLC_USERPROPCOLLIMIT 0xff
140 #define SVNSLC_MAXCOLUMNCOUNT 0xff
142 // Supporting extreamly long user props makes no sense here --
143 // especially for binary properties. CString uses a pool allocator
144 // that works for up to 256 chars. Make sure we are well below that.
146 #define SVNSLC_MAXUSERPROPLENGTH 0x70
148 typedef int (__cdecl
*GENERICCOMPAREFN
)(const void * elem1
, const void * elem2
);
149 typedef CComCritSecLock
<CComCriticalSection
> Locker
;
151 class CGitStatusListCtrlDropTarget
;
154 * \ingroup TortoiseProc
155 * Helper class for CGitStatusListCtrl that represents
156 * the columns visible and their order as well as
157 * persisting that data in the registry.
159 * It assigns logical index values to the (potential) columns:
160 * 0 .. GitSLC_NUMCOLUMNS-1 contain the standard attributes
161 * GitSLC_USERPROPCOLOFFSET .. GitSLC_MAXCOLUMNCOUNT are user props.
163 * The column vector contains the columns that are actually
164 * available in the control.
166 * Since the set of userprops may change from one WC to another,
167 * we also store the settings (width and order) for those
168 * userprops that are not used in this WC.
170 * A userprop is considered "in use", if the respective column
171 * is not hidden or if at least one item has this property set.
177 /// construction / destruction
179 ColumnManager (CListCtrl
* control
) : control (control
) {};
182 DWORD m_dwDefaultColumns
;
185 void ReadSettings (DWORD defaultColumns
, DWORD hideColumns
, const CString
& containerName
, int ReadSettings
, int *withlist
=NULL
);
186 void WriteSettings() const;
188 /// read column definitions
190 int GetColumnCount() const; ///< total number of columns
191 bool IsVisible (int column
) const;
192 int GetInvisibleCount() const;
193 bool IsRelevant (int column
) const;
194 bool IsUserProp (int column
) const;
195 CString
GetName (int column
) const;
196 int SetNames(UINT
* buff
, int size
);
197 int GetWidth (int column
, bool useDefaults
= false) const;
198 int GetVisibleWidth (int column
, bool useDefaults
) const;
200 /// switch columns on and off
202 void SetVisible (int column
, bool visible
);
204 /// tracking column modifications
206 void ColumnMoved (int column
, int position
);
207 void ColumnResized (int column
);
209 /// call these to update the user-prop list
210 /// (will also auto-insert /-remove new list columns)
212 //void UpdateUserPropList (const std::vector<FileEntry*>& files);
213 //void UpdateRelevance ( const std::vector<FileEntry*>& files
214 // , const std::vector<size_t>& visibleFiles);
216 /// don't clutter the context menu with irrelevant prop info
218 bool AnyUnusedProperties() const;
219 void RemoveUnusedProps();
221 /// bring everything back to its "natural" order
223 void ResetColumns (DWORD defaultColumns
);
225 void OnColumnResized(NMHDR
*pNMHDR
, LRESULT
*pResult
)
227 LPNMHEADER header
= reinterpret_cast<LPNMHEADER
>(pNMHDR
);
228 if ( (header
!= NULL
)
229 && (header
->iItem
>= 0)
230 && (header
->iItem
< GetColumnCount()))
232 ColumnResized (header
->iItem
);
237 void OnColumnMoved(NMHDR
*pNMHDR
, LRESULT
*pResult
)
239 LPNMHEADER header
= reinterpret_cast<LPNMHEADER
>(pNMHDR
);
241 if ( (header
!= NULL
)
242 && (header
->iItem
>= 0)
243 && (header
->iItem
< GetColumnCount())
244 // only allow the reordering if the column was not moved left of the first
245 // visible item - otherwise the 'invisible' columns are not at the far left
246 // anymore and we get all kinds of redrawing problems.
248 && (header
->pitem
->iOrder
> GetInvisibleCount()))
250 ColumnMoved (header
->iItem
, header
->pitem
->iOrder
);
255 void OnHdnBegintrack(NMHDR
*pNMHDR
, LRESULT
*pResult
)
257 LPNMHEADER phdr
= reinterpret_cast<LPNMHEADER
>(pNMHDR
);
259 if ((phdr
->iItem
< 0)||(phdr
->iItem
>= itemName
.size()))
262 if (IsVisible (phdr
->iItem
))
269 int OnHdnItemchanging(NMHDR
*pNMHDR
, LRESULT
*pResult
)
271 LPNMHEADER phdr
= reinterpret_cast<LPNMHEADER
>(pNMHDR
);
273 if ((phdr
->iItem
< 0)||(phdr
->iItem
>= itemName
.size()))
278 // visible columns may be modified
280 if (IsVisible (phdr
->iItem
))
285 // columns already marked as "invisible" internally may be (re-)sized to 0
287 if ( (phdr
->pitem
!= NULL
)
288 && (phdr
->pitem
->mask
== HDI_WIDTH
)
289 && (phdr
->pitem
->cxy
== 0))
294 if ( (phdr
->pitem
!= NULL
)
295 && (phdr
->pitem
->mask
!= HDI_WIDTH
))
303 void OnContextMenuHeader(CWnd
* pWnd
, CPoint point
, bool isGroundEnable
=false)
305 bool XPorLater
= false;
307 SecureZeroMemory(&inf
, sizeof(OSVERSIONINFOEX
));
308 inf
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFOEX
);
309 GetVersionEx((OSVERSIONINFO
*)&inf
);
310 WORD fullver
= MAKEWORD(inf
.dwMinorVersion
, inf
.dwMajorVersion
);
311 if (fullver
>= 0x0501)
314 CHeaderCtrl
* pHeaderCtrl
= (CHeaderCtrl
*)pWnd
;
315 if ((point
.x
== -1) && (point
.y
== -1))
318 pHeaderCtrl
->GetItemRect(0, &rect
);
319 pHeaderCtrl
->ClientToScreen(&rect
);
320 point
= rect
.CenterPoint();
324 if (popup
.CreatePopupMenu())
326 int columnCount
= GetColumnCount();
329 UINT uCheckedFlags
= MF_STRING
| MF_ENABLED
| MF_CHECKED
;
330 UINT uUnCheckedFlags
= MF_STRING
| MF_ENABLED
;
332 // build control menu
336 //temp.LoadString(IDS_STATUSLIST_SHOWGROUPS);
337 //popup.AppendMenu(isGroundEnable? uCheckedFlags : uUnCheckedFlags, columnCount, temp);
340 if (AnyUnusedProperties())
342 temp
.LoadString(IDS_STATUSLIST_REMOVEUNUSEDPROPS
);
343 popup
.AppendMenu(uUnCheckedFlags
, columnCount
+1, temp
);
346 temp
.LoadString(IDS_STATUSLIST_RESETCOLUMNORDER
);
347 popup
.AppendMenu(uUnCheckedFlags
, columnCount
+2, temp
);
348 popup
.AppendMenu(MF_SEPARATOR
);
353 // user-prop columns:
354 // find relevant ones and sort 'em
356 std::map
<CString
, int> sortedProps
;
357 for (int i
= itemName
.size(); i
< columnCount
; ++i
)
359 sortedProps
[GetName(i
)] = i
;
361 if (!sortedProps
.empty())
363 // add 'em to the menu
365 popup
.AppendMenu(MF_SEPARATOR
);
367 typedef std::map
<CString
, int>::const_iterator CIT
;
368 for ( CIT iter
= sortedProps
.begin(), end
= sortedProps
.end()
372 popup
.AppendMenu ( IsVisible(iter
->second
)
380 // show menu & let user pick an entry
382 int cmd
= popup
.TrackPopupMenu(TPM_RETURNCMD
| TPM_LEFTALIGN
| TPM_NONOTIFY
, point
.x
, point
.y
, pWnd
, 0);
383 if ((cmd
>= 1)&&(cmd
< columnCount
))
385 SetVisible (cmd
, !IsVisible(cmd
));
387 else if (cmd
== columnCount
)
389 pWnd
->GetParent()->SendMessage(LVM_ENABLEGROUPVIEW
, !isGroundEnable
, NULL
);
390 //EnableGroupView(!isGroundEnable);
392 else if (cmd
== columnCount
+1)
396 else if (cmd
== columnCount
+2)
398 ResetColumns (m_dwDefaultColumns
);
403 void AddMenuItem(CMenu
*pop
)
405 UINT uCheckedFlags
= MF_STRING
| MF_ENABLED
| MF_CHECKED
;
406 UINT uUnCheckedFlags
= MF_STRING
| MF_ENABLED
;
408 for (int i
= 1; i
< itemName
.size(); ++i
)
411 pop
->AppendMenu ( IsVisible(i
)
420 /// initialization utilities
422 void ParseUserPropSettings ( const CString
& userPropList
423 , const CString
& shownUserProps
);
424 void ParseWidths (const CString
& widths
);
425 void SetStandardColumnVisibility (DWORD visibility
);
426 void ParseColumnOrder (const CString
& widths
);
428 /// map internal column order onto visible column order
429 /// (all invisibles in front)
431 std::vector
<int> GetGridColumnOrder();
432 void ApplyColumnOrder();
434 /// utilities used when writing data to the registry
436 DWORD
GetSelectedStandardColumns() const;
437 CString
GetUserPropList() const;
438 CString
GetShownUserProps() const;
439 CString
GetWidthString() const;
440 CString
GetColumnOrderString() const;
442 /// our parent control and its data
446 /// where to store in the registry
448 CString registryPrefix
;
450 /// all columns in their "natural" order
454 int index
; ///< is a user prop when < GitSLC_USERPROPCOLOFFSET
457 bool relevant
; ///< set to @a visible, if no *shown* item has that property
460 std::vector
<ColumnInfo
> columns
;
462 /// user-defined properties
466 CString name
; ///< is a user prop when < GitSLC_USERPROPCOLOFFSET
470 std::vector
<UserProp
> userProps
;
472 /// stored result from last UpdateUserPropList() call
474 std::set
<CString
> itemProps
;
476 /// global column ordering including unused user props
478 std::vector
<int> columnOrder
;
480 std::vector
<int> itemName
;
485 * \ingroup TortoiseProc
486 * Simple utility class that defines the sort column order.
492 CSorter ( ColumnManager
* columnManager
496 bool operator() ( const CTGitPath
* entry1
497 , const CTGitPath
* entry2
) const;
499 static int A2L(const CString
&str
)
509 ColumnManager
* columnManager
;
516 * A List control, based on the MFC CListCtrl which shows a list of
517 * files with their Subversion status. The control also provides a context
518 * menu to do some Subversion tasks on the selected files.
520 * This is the main control used in many dialogs to show a list of files to
523 class CGitStatusListCtrl
:
537 IDSVNLC_EDITCONFLICT
,
540 IDSVNLC_RESOLVECONFLICT
,
544 IDSVNLC_UNLOCKFORCE
,
547 IDSVNLC_RESOLVETHEIRS
,
548 IDSVNLC_RESOLVEMINE
,
555 IDSVNLC_REMOVEFROMCS
,
557 IDSVNLC_CREATEIGNORECS
,
559 IDSVNLC_UNCHECKGROUP
,
560 IDSVNLC_ADD_RECURSIVE
,
564 IDSVNLC_REVERTTOREV
,
569 // the IDSVNLC_MOVETOCS *must* be the last index, because it contains a dynamic submenu where
570 // the submenu items get command ID's sequent to this number
573 int GetColumnIndex(int colmask
);
574 static inline unsigned __int64
GetContextMenuBit(int i
){ return ((unsigned __int64
)0x1)<<i
;}
576 * Sent to the parent window (using ::SendMessage) after a context menu
577 * command has finished if the item count has changed.
579 static const UINT SVNSLNM_ITEMCOUNTCHANGED
;
581 * Sent to the parent window (using ::SendMessage) when the control needs
582 * to be refreshed. Since this is done usually in the parent window using
583 * a thread, this message is used to tell the parent to do exactly that.
585 static const UINT SVNSLNM_NEEDSREFRESH
;
588 * Sent to the parent window (using ::SendMessage) when the user drops
589 * files on the control. The LPARAM is a pointer to a TCHAR string
590 * containing the dropped path.
592 static const UINT SVNSLNM_ADDFILE
;
595 * Sent to the parent window (using ::SendMessage) when the user checks/unchecks
596 * one or more items in the control. The WPARAM contains the number of
597 * checked items in the control.
599 static const UINT SVNSLNM_CHECKCHANGED
;
601 static const UINT SVNSLNM_ITEMCHANGED
;
603 CGitStatusListCtrl(void);
604 ~CGitStatusListCtrl(void);
610 * \ingroup TortoiseProc
611 * Helper class for CGitStatusListCtrl which represents
612 * the data for each file shown.
618 FileEntry() : status(git_wc_status_unversioned
)
619 // , copyfrom_rev(GIT_REV_ZERO)
620 , last_commit_date(0)
621 , last_commit_rev(GIT_REV_ZERO
)
622 // , remoterev(GIT_REV_ZERO)
623 , textstatus(git_wc_status_unversioned
)
624 , propstatus(git_wc_status_unversioned
)
625 // , remotestatus(git_wc_status_unversioned)
626 // , remotetextstatus(git_wc_status_unversioned)
627 // , remotepropstatus(git_wc_status_unversioned)
631 , inunversionedfolder(false)
633 , differentrepo(false)
637 , Revision(GIT_REV_ZERO
)
638 , isConflicted(false)
641 /// , working_size(SVN_WC_ENTRY_WORKING_SIZE_UNKNOWN)
643 // , depth(git_depth_unknown)
646 const CTGitPath
& GetPath() const
650 const bool IsChecked() const
654 CString
GetRelativeGitPath() const
656 if (path
.IsEquivalentTo(basepath
))
657 return path
.GetGitPathString();
658 return path
.GetGitPathString().Mid(basepath
.GetGitPathString().GetLength()+1);
660 // const bool IsLocked() const
662 // return !(lock_token.IsEmpty() && lock_remotetoken.IsEmpty());
664 // const bool HasNeedsLock() const
668 const bool IsFolder() const
672 const bool IsInExternal() const
676 const bool IsNested() const
680 const bool IsFromDifferentRepository() const
682 return differentrepo
;
684 CString
GetDisplayName() const
686 CString
const& chopped
= path
.GetDisplayString(&basepath
);
687 if (!chopped
.IsEmpty())
693 // "Display name" must not be empty.
694 return path
.GetFileOrDirectoryName();
697 CString
GetChangeList() const
701 // CString GetURL() const
706 git_wc_status_kind status
; ///< local status
707 git_wc_status_kind textstatus
; ///< local text status
708 git_wc_status_kind propstatus
; ///< local property status
711 CTGitPath path
; ///< full path of the file
712 CTGitPath basepath
; ///< common ancestor path of all files
714 CString changelist
; ///< the name of the changelist the item belongs to
716 CString last_commit_author
; ///< the author which last committed this item
717 CTime last_commit_date
; ///< the date when this item was last committed
718 git_revnum_t last_commit_rev
; ///< the revision where this item was last committed
720 git_revnum_t remoterev
; ///< the revision in HEAD of the repository
721 bool copied
; ///< if the file/folder is added-with-history
722 bool switched
; ///< if the file/folder is switched to another url
723 bool checked
; ///< if the file is checked in the list control
724 bool inunversionedfolder
; ///< if the file is inside an unversioned folder
725 bool inexternal
; ///< if the item is in an external folder
726 bool differentrepo
; ///< if the item is from a different repository than the rest
727 bool direct
; ///< directly included (TRUE) or just a child of a folder
728 bool isfolder
; ///< TRUE if entry refers to a folder
729 bool isNested
; ///< TRUE if the folder from a different repository and/or path
730 bool isConflicted
; ///< TRUE if a file entry is conflicted, i.e. if it has the conflicted paths set
731 bool needslock
; ///< TRUE if the Git:needs-lock property is set
732 git_revnum_t Revision
; ///< the base revision
733 // PropertyList present_props; ///< cacheable properties present in BASE
734 bool keeplocal
; ///< Whether a local copy of this entry should be kept in the working copy after a deletion has been committed
735 git_depth_t depth
; ///< the depth of this entry
736 friend class CGitStatusListCtrl
;
737 friend class CGitStatusListCtrlDropTarget
;
738 friend class CSorter
;
743 * Initializes the control, sets up the columns.
744 * \param dwColumns mask of columns to show. Use the GitSLC_COLxxx defines.
745 * \param sColumnInfoContainer Name of a registry key
746 * where the position and visibility of each column
747 * is saved and used from. If the registry key
748 * doesn't exist, the default order is used
749 * and dwColumns tells which columns are visible.
750 * \param dwContextMenus mask of context menus to be active, not all make sense for every use of this control.
751 * Use the GitSLC_POPxxx defines.
752 * \param bHasCheckboxes TRUE if the control should show check boxes on the left of each file entry.
754 void Init(DWORD dwColumns
, const CString
& sColumnInfoContainer
, unsigned __int64 dwContextMenus
= (SVNSLC_POPALL
^ SVNSLC_POPCOMMIT
), bool bHasCheckboxes
= true);
756 * Sets a background image for the list control.
757 * The image is shown in the right bottom corner.
758 * \param nID the resource ID of the bitmap to use as the background
760 bool SetBackgroundImage(UINT nID
);
762 * Makes the 'ignore' context menu only ignore the files and not add the
763 * folder which gets the Git:ignore property changed to the list.
764 * This is needed e.g. for the Add-dialog, where the modified folder
765 * showing up would break the resulting "add" command.
767 void SetIgnoreRemoveOnly(bool bRemoveOnly
= true) {m_bIgnoreRemoveOnly
= bRemoveOnly
;}
769 * The unversioned items are by default shown after all other files in the list.
770 * If that behavior should be changed, set this value to false.
772 void PutUnversionedLast(bool bLast
) {m_bUnversionedLast
= bLast
;}
774 * Fetches the Subversion status of all files and stores the information
775 * about them in an internal array.
776 * \param sFilePath path to a file which contains a list of files and/or folders for which to
777 * fetch the status, separated by newlines.
778 * \param bUpdate TRUE if the remote status is requested too.
779 * \return TRUE on success.
781 BOOL
GetStatus ( const CTGitPathList
* pathList
=NULL
782 , bool bUpdate
= false
783 , bool bShowIgnores
= false
784 , bool bShowUnRev
=false
785 , bool bShowUserProps
= false);
788 * Populates the list control with the previously (with GetStatus) gathered status information.
789 * \param dwShow mask of file types to show. Use the GitSLC_SHOWxxx defines.
790 * \param dwCheck mask of file types to check. Use GitLC_SHOWxxx defines. Default (0) means 'use the entry's stored check status'
792 void Show(DWORD dwShow
, DWORD dwCheck
= 0, bool bShowFolders
= true,BOOL updateStatusList
=FALSE
, bool UseStoredCheckStatus
=false);
793 void Show(DWORD dwShow
, const CTGitPathList
& checkedList
, bool bShowFolders
= true);
796 * Copies the selected entries in the control to the clipboard. The entries
797 * are separated by newlines.
798 * \param dwCols the columns to copy. Each column is separated by a tab.
800 bool CopySelectedEntriesToClipboard(DWORD dwCols
);
803 * If during the call to GetStatus() some Git:externals are found from different
804 * repositories than the first one checked, then this method returns TRUE.
806 BOOL
HasExternalsFromDifferentRepos() const {return m_bHasExternalsFromDifferentRepos
;}
809 * If during the call to GetStatus() some Git:externals are found then this method returns TRUE.
811 BOOL
HasExternals() const {return m_bHasExternals
;}
814 * If unversioned files are found (but not necessarily shown) TRUE is returned.
816 BOOL
HasUnversionedItems() {return m_bHasUnversionedItems
;}
819 * If there are any locks in the working copy, TRUE is returned
821 BOOL
HasLocks() const {return m_bHasLocks
;}
824 * If there are any change lists defined in the working copy, TRUE is returned
826 BOOL
HasChangeLists() const {return m_bHasChangeLists
;}
829 * Returns the file entry data for the list control index.
831 //CGitStatusListCtrl::FileEntry * GetListEntry(UINT_PTR index);
834 * Returns the file entry data for the specified path.
835 * \note The entry might not be shown in the list control.
837 //CGitStatusListCtrl::FileEntry * GetListEntry(const CTGitPath& path);
840 * Returns the index of the list control entry with the specified path,
841 * or -1 if the path is not in the list control.
843 int GetIndex(const CTGitPath
& path
);
846 * Returns the file entry data for the specified path in the list control.
848 //CGitStatusListCtrl::FileEntry * GetVisibleListEntry(const CTGitPath& path);
851 * Returns a String containing some statistics like number of modified, normal, deleted,...
854 CString
GetStatisticsString(bool simple
=false);
857 * Set a static control which will be updated automatically with
858 * the number of selected and total files shown in the list control.
860 void SetStatLabel(CWnd
* pStatLabel
){m_pStatLabel
= pStatLabel
;};
863 * Set a tri-state checkbox which is updated automatically if the
864 * user checks/unchecks file entries in the list control to indicate
865 * if all files are checked, none are checked or some are checked.
867 void SetSelectButton(CButton
* pButton
) {m_pSelectButton
= pButton
;}
870 * Set a button which is de-/activated automatically. The button is
871 * only set active if at least one item is selected.
873 void SetConfirmButton(CButton
* pButton
) {m_pConfirmButton
= pButton
;}
876 * Select/unselect all entries in the list control.
877 * \param bSelect TRUE to check, FALSE to uncheck.
879 void SelectAll(bool bSelect
, bool bIncludeNoCommits
= false);
881 /** Set a checkbox on an entry in the listbox
882 * Keeps the listctrl checked state and the FileEntry's checked flag in sync
884 void SetEntryCheck(CTGitPath
* pEntry
, int listboxIndex
, bool bCheck
);
886 /** Write a list of the checked items' paths into a path list
888 void WriteCheckedNamesToPathList(CTGitPathList
& pathList
);
890 /** fills in \a lMin and \a lMax with the lowest/highest revision of all
891 * files/folders in the working copy.
892 * \param bShownOnly if true, the min/max revisions are calculated only for shown items
893 * \param bCheckedOnly if true, the min/max revisions are calculated only for items
895 * \remark Since an item can only be checked if it is visible/shown in the list control
896 * bShownOnly is automatically set to true if bCheckedOnly is true
898 void GetMinMaxRevisions(git_revnum_t
& rMin
, git_revnum_t
& rMax
, bool bShownOnly
, bool bCheckedOnly
);
901 * Returns the parent directory of all entries in the control.
902 * if \a bStrict is set to false, then the paths passed to the control
903 * to fetch the status (in GetStatus()) are used if possible.
905 CString
GetCommonDirectory(bool bStrict
);
908 * Returns the parent url of all entries in the control.
909 * if \a bStrict is set to false, then the paths passed to the control
910 * to fetch the status (in GetStatus()) are used if possible.
912 CTGitPath
GetCommonURL(bool bStrict
);
915 * Sets a pointer to a boolean variable which is checked periodically
916 * during the status fetching. As soon as the variable changes to true,
917 * the operations stops.
919 void SetCancelBool(bool * pbCanceled
) {m_pbCanceled
= pbCanceled
;}
922 * Sets the string shown in the control while the status is fetched.
923 * If not set, it defaults to "please wait..."
925 void SetBusyString(const CString
& str
) {m_sBusy
= str
;}
926 void SetBusyString(UINT id
) {m_sBusy
.LoadString(id
);}
929 * Sets the string shown in the control if no items are shown. This
930 * can happen for example if there's nothing modified and the unversioned
931 * files aren't shown either, so there's nothing to commit.
932 * If not set, it defaults to "file list is empty".
934 void SetEmptyString(const CString
& str
) {m_sEmpty
= str
;}
935 void SetEmptyString(UINT id
) {m_sEmpty
.LoadString(id
);}
938 * Determines if the control should recurse into unversioned folders
939 * when fetching the status. The default behavior is defined by the
940 * registry key HKCU\Software\TortoiseGit\UnversionedRecurse, which
941 * is read in the Init() method.
942 * If you want to change the behavior, call this method *after*
945 void SetUnversionedRecurse(bool bUnversionedRecurse
) {m_bUnversionedRecurse
= bUnversionedRecurse
;}
948 * Returns the number of selected items
950 LONG
GetSelected(){return m_nSelected
;};
953 * Enables dropping of files on the control.
955 bool EnableFileDrop();
958 * Checks if the path already exists in the list.
960 bool HasPath(const CTGitPath
& path
);
962 * Checks if the path is shown/visible in the list control.
964 bool IsPathShown(const CTGitPath
& path
);
966 * Forces the children to be checked when the parent folder is checked,
967 * and the parent folder to be unchecked if one of its children is unchecked.
969 void CheckChildrenWithParent(bool bCheck
) {m_bCheckChildrenWithParent
= bCheck
;}
972 * Allows checking the items if change lists are present. If set to false,
973 * items are not checked if at least one changelist is available.
975 void CheckIfChangelistsArePresent(bool bCheck
) {m_bCheckIfGroupsExist
= bCheck
;}
977 * Returns the currently used show flags passed to the Show() method.
979 DWORD
GetShowFlags() {return m_dwShow
;}
981 CString
GetLastErrorMessage() {return m_sLastError
;}
983 void Block(BOOL block
, BOOL blockUI
) {m_bBlock
= block
; m_bBlockUI
= blockUI
;}
985 LONG m_nTargetCount
; ///< number of targets in the file passed to GetStatus()
987 CString m_sURL
; ///< the URL of the target or "(multiple targets)"
989 GitRev m_HeadRev
; ///< the HEAD revision of the repository if bUpdate was TRUE
991 CString m_sUUID
; ///< the UUID of the associated repository
993 bool m_bIsRevertTheirMy
; ///< at rebase case, Their and My version is revert.
995 DECLARE_MESSAGE_MAP()
998 void SetBusy(bool b
) {m_bBusy
= b
; Invalidate();}
1001 void SaveColumnWidths(bool bSaveToRegistry
= false);
1002 void Sort(); ///< Sorts the control by columns
1003 //void AddEntry(FileEntry * entry, WORD langID, int listIndex); ///< add an entry to the control
1004 void RemoveListEntry(int index
); ///< removes an entry from the listcontrol and both arrays
1005 bool BuildStatistics(); ///< build the statistics and correct the case of files/folders
1006 void StartDiff(int fileindex
); ///< start the external diff program
1007 void StartDiffWC(int fileindex
); ///< start the external diff program
1008 void StartDiffTwo(int fileindex
);
1016 void OpenFile(CTGitPath
*path
,int mode
);
1018 /// fetch all user properties for all items
1019 void FetchUserProperties();
1021 /// Process one line of the command file supplied to GetStatus
1022 bool FetchStatusForSingleTarget(GitConfig
& config
, GitStatus
& status
, const CTGitPath
& target
,
1023 bool bFetchStatusFromRepository
, CStringA
& strCurrentRepositoryUUID
, CTGitPathList
& arExtPaths
,
1024 bool bAllDirect
, git_depth_t depth
= git_depth_infinity
, bool bShowIgnores
= false);
1026 /// Create 'status' data for each item in an unversioned folder
1027 void AddUnversionedFolder(const CTGitPath
& strFolderName
, const CTGitPath
& strBasePath
, GitConfig
* config
);
1029 /// Read the all the other status items which result from a single GetFirstStatus call
1030 void ReadRemainingItemsStatus(GitStatus
& status
, const CTGitPath
& strBasePath
, CStringA
& strCurrentRepositoryUUID
, CTGitPathList
& arExtPaths
, GitConfig
* config
, bool bAllDirect
);
1032 /// Clear the status vector (contains custodial pointers)
1033 void ClearStatusArray();
1035 /// Sort predicate function - Compare the paths of two entries without regard to case
1036 //static bool EntryPathCompareNoCase(const FileEntry* pEntry1, const FileEntry* pEntry2);
1038 /// Predicate used to build a list of only the versioned entries of the FileEntry array
1039 //static bool IsEntryVersioned(const FileEntry* pEntry1);
1041 /// Look up the relevant show flags for a particular Git status value
1042 DWORD
GetShowFlagsFromGitStatus(git_wc_status_kind status
);
1044 /// Build a FileEntry item and add it to the FileEntry array
1045 //const FileEntry* AddNewFileEntry(
1046 // const git_wc_status2_t* pGitStatus, // The return from the Git GetStatus functions
1047 // const CTGitPath& path, // The path of the item we're adding
1048 // const CTGitPath& basePath, // The base directory for this status build
1049 // bool bDirectItem, // Was this item the first found by GetFirstFileStatus or by a subsequent GetNextFileStatus call
1050 // bool bInExternal, // Are we in an 'external' folder
1051 // bool bEntryfromDifferentRepo // if the entry is from a different repository
1054 /// Adjust the checkbox-state on all descendants of a specific item
1055 //void SetCheckOnAllDescendentsOf(const FileEntry* parentEntry, bool bCheck);
1057 /// Build a path list of all the selected items in the list (NOTE - SELECTED, not CHECKED)
1058 void FillListOfSelectedItemPaths(CTGitPathList
& pathList
, bool bNoIgnored
= false);
1060 /// Enables/Disables group view and adds all groups to the list control.
1061 /// If bForce is true, then group view is enabled and the 'null' group is added.
1062 bool PrepareGroups(bool bForce
= false);
1063 /// Returns the group number to which the group header belongs
1064 /// If the point is not over a group header, -1 is returned
1065 int GetGroupFromPoint(POINT
* ppt
);
1066 /// Returns the number of change lists the selection has
1067 size_t GetNumberOfChangelistsInSelection();
1069 /// Puts the item to the corresponding group
1070 bool SetItemGroup(int item
, int groupindex
);
1072 void CheckEntry(int index
, int nListItems
);
1073 void UncheckEntry(int index
, int nListItems
);
1075 /// sends an GitSLNM_CHECKCHANGED notification to the parent
1078 int CellRectFromPoint(CPoint
& point
, RECT
*cellrect
, int *col
) const;
1080 void OnContextMenuList(CWnd
* pWnd
, CPoint point
);
1081 void OnContextMenuGroup(CWnd
* pWnd
, CPoint point
);
1082 void OnContextMenuHeader(CWnd
* pWnd
, CPoint point
);
1084 virtual void PreSubclassWindow();
1085 virtual BOOL
PreTranslateMessage(MSG
* pMsg
);
1086 virtual INT_PTR
OnToolHitTest(CPoint point
, TOOLINFO
* pTI
) const;
1087 afx_msg
void OnBeginDrag(NMHDR
* pNMHDR
, LRESULT
* pResult
);
1088 afx_msg BOOL
OnToolTipText(UINT id
, NMHDR
*pNMHDR
, LRESULT
*pResult
);
1089 afx_msg
void OnHdnItemclick(NMHDR
*pNMHDR
, LRESULT
*pResult
);
1090 afx_msg
void OnLvnItemchanging(NMHDR
*pNMHDR
, LRESULT
*pResult
);
1091 afx_msg BOOL
OnLvnItemchanged(NMHDR
*pNMHDR
, LRESULT
*pResult
);
1092 afx_msg
void OnColumnResized(NMHDR
*pNMHDR
, LRESULT
*pResult
);
1093 afx_msg
void OnColumnMoved(NMHDR
*pNMHDR
, LRESULT
*pResult
);
1094 afx_msg
void OnContextMenu(CWnd
* pWnd
, CPoint point
);
1096 void CreateChangeList(const CString
& name
);
1098 afx_msg
void OnNMDblclk(NMHDR
*pNMHDR
, LRESULT
*pResult
);
1099 afx_msg
void OnLvnGetInfoTip(NMHDR
*pNMHDR
, LRESULT
*pResult
);
1100 afx_msg
void OnNMCustomdraw(NMHDR
*pNMHDR
, LRESULT
*pResult
);
1101 afx_msg BOOL
OnSetCursor(CWnd
* pWnd
, UINT nHitTest
, UINT message
);
1102 afx_msg UINT
OnGetDlgCode();
1103 afx_msg
void OnNMReturn(NMHDR
*pNMHDR
, LRESULT
*pResult
);
1104 afx_msg
void OnKeyDown(UINT nChar
, UINT nRepCnt
, UINT nFlags
);
1105 afx_msg
void OnPaint();
1106 afx_msg
void OnHdnBegintrack(NMHDR
*pNMHDR
, LRESULT
*pResult
);
1107 afx_msg
void OnHdnItemchanging(NMHDR
*pNMHDR
, LRESULT
*pResult
);
1108 afx_msg
void OnDestroy();
1111 void FileSaveAs(CTGitPath
*path
);
1112 int RevertSelectedItemToVersion();
1115 bool * m_pbCanceled
;
1116 bool m_bAscending
; ///< sort direction
1117 int m_nSortedColumn
; ///< which column to sort
1118 bool m_bHasCheckboxes
;
1119 bool m_bUnversionedLast
;
1120 bool m_bHasExternalsFromDifferentRepos
;
1121 bool m_bHasExternals
;
1122 BOOL m_bHasUnversionedItems
;
1124 bool m_bHasChangeLists
;
1125 //typedef std::vector<FileEntry*> FileEntryVector;
1126 //FileEntryVector m_arStatusArray;
1127 std::vector
<CTGitPath
*> m_arStatusArray
;
1128 std::vector
<size_t> m_arListArray
;
1129 std::map
<CString
, int> m_changelists
;
1130 bool m_bHasIgnoreGroup
;
1131 //CTGitPathList m_ConflictFileList;
1132 CTGitPathList m_StatusFileList
;
1133 CTGitPathList m_UnRevFileList
;
1134 CTGitPathList m_IgnoreFileList
;
1135 //CTGitPathList m_StatusUrlList;
1136 CString m_sLastError
;
1138 LONG m_nUnversioned
;
1147 LONG m_nLineDeleted
;
1150 DWORD m_dwDefaultColumns
;
1152 bool m_bShowFolders
;
1153 bool m_bShowIgnores
;
1155 unsigned __int64 m_dwContextMenus
;
1160 bool m_bIgnoreRemoveOnly
;
1161 bool m_bCheckIfGroupsExist
;
1162 bool m_bFileDropsEnabled
;
1167 CWnd
* m_pStatLabel
;
1168 CButton
* m_pSelectButton
;
1169 CButton
* m_pConfirmButton
;
1174 CString m_sNoPropValueText
;
1176 bool m_bUnversionedRecurse
;
1178 bool m_bCheckChildrenWithParent
;
1179 CGitStatusListCtrlDropTarget
* m_pDropTarget
;
1181 ColumnManager m_ColumnManager
;
1183 std::map
<CString
,bool> m_mapFilenameToChecked
; ///< Remember manually de-/selected items
1184 CComCriticalSection m_critSec
;
1186 friend class CGitStatusListCtrlDropTarget
;
1190 FILELIST_MODIFY
= 0x1,
1191 FILELIST_UNVER
= 0x2,
1192 FILELIST_IGNORE
=0x4
1195 int UpdateFileList(git_revnum_t hash
,CTGitPathList
*List
=NULL
);
1196 int UpdateFileList(int mask
, bool once
=true,CTGitPathList
*List
=NULL
);
1197 int UpdateUnRevFileList(CTGitPathList
*List
=NULL
);
1198 int UpdateIgnoreFileList(CTGitPathList
*List
=NULL
);
1200 int UpdateWithGitPathList(CTGitPathList
&list
);
1202 void AddEntry(CTGitPath
* path
, WORD langID
, int ListIndex
);
1205 git_revnum_t m_CurrentVersion
;
1211 class CGitStatusListCtrlDropTarget
: public CIDropTarget
1214 CGitStatusListCtrlDropTarget(CGitStatusListCtrl
* pGitStatusListCtrl
):CIDropTarget(pGitStatusListCtrl
->m_hWnd
){m_pGitStatusListCtrl
= pGitStatusListCtrl
;}
1216 virtual bool OnDrop(FORMATETC
* pFmtEtc
, STGMEDIUM
& medium
, DWORD
* /*pdwEffect*/, POINTL pt
);
1217 virtual HRESULT STDMETHODCALLTYPE
DragOver(DWORD grfKeyState
, POINTL pt
, DWORD __RPC_FAR
*pdwEffect
);
1219 CGitStatusListCtrl
* m_pGitStatusListCtrl
;