1 // TortoiseSVN - a Windows shell extension for easy version control
\r
3 // Copyright (C) 2003-2008 - TortoiseSVN
\r
5 // This program is free software; you can redistribute it and/or
\r
6 // modify it under the terms of the GNU General Public License
\r
7 // as published by the Free Software Foundation; either version 2
\r
8 // of the License, or (at your option) any later version.
\r
10 // This program is distributed in the hope that it will be useful,
\r
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
13 // GNU General Public License for more details.
\r
15 // You should have received a copy of the GNU General Public License
\r
16 // along with this program; if not, write to the Free Software Foundation,
\r
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
\r
20 #include "TGitPath.h"
\r
21 #include "GitStatus.h"
\r
23 #include "GitConfig.h"
\r
25 #include "XPTheme.h"
\r
27 #define SVN_WC_ENTRY_WORKING_SIZE_UNKNOWN (-1)
\r
29 // these defines must be in the order the columns are inserted!
\r
30 #define SVNSLC_COLFILENAME 0x000000002
\r
31 #define SVNSLC_COLEXT 0x000000004
\r
32 #define SVNSLC_COLSTATUS 0x000000008
\r
33 #define SVNSLC_COLTEXTSTATUS 0x000000010
\r
34 #define SVNSLC_COLPROPSTATUS 0x000000020
\r
35 #define SVNSLC_COLAUTHOR 0x000000040
\r
36 #define SVNSLC_COLREVISION 0x000000080
\r
37 #define SVNSLC_COLDATE 0x000000100
\r
38 #define SVNSLC_COLMODIFICATIONDATE 0x000000200
\r
39 #define SVNSLC_COLADD 0x000000400
\r
40 #define SVNSLC_COLDEL 0x000000800
\r
41 #define SVNSLC_NUMCOLUMNS 12
\r
43 //#define SVNSLC_COLREMOTESTATUS 0x000000010
\r
44 //#define SVNSLC_COLREMOTETEXT 0x000000080
\r
45 //#define SVNSLC_COLREMOTEPROP 0x000000100
\r
46 //#define SVNSLC_COLURL 0x000000200
\r
47 //#define SVNSLC_COLLOCK 0x000000400
\r
48 //#define SVNSLC_COLLOCKCOMMENT 0x000000800
\r
50 //#define SVNSLC_COLREMOTEREVISION 0x000004000
\r
52 //#define SVNSLC_COLSVNNEEDSLOCK 0x000010000
\r
53 //#define SVNSLC_COLCOPYFROM 0x000020000
\r
56 #define SVNSLC_SHOWUNVERSIONED CTGitPath::LOGACTIONS_UNVER
\r
57 #define SVNSLC_SHOWNORMAL 0x000000000
\r
58 #define SVNSLC_SHOWMODIFIED (CTGitPath::LOGACTIONS_MODIFIED)
\r
59 #define SVNSLC_SHOWADDED (CTGitPath::LOGACTIONS_ADDED|CTGitPath::LOGACTIONS_COPY)
\r
60 #define SVNSLC_SHOWREMOVED CTGitPath::LOGACTIONS_DELETED
\r
61 #define SVNSLC_SHOWCONFLICTED CTGitPath::LOGACTIONS_UNMERGED
\r
62 #define SVNSLC_SHOWMISSING 0x00000000
\r
63 #define SVNSLC_SHOWREPLACED CTGitPath::LOGACTIONS_REPLACED
\r
64 #define SVNSLC_SHOWMERGED 0x00000000
\r
65 #define SVNSLC_SHOWIGNORED CTGitPath::LOGACTIONS_IGNORE
\r
66 #define SVNSLC_SHOWOBSTRUCTED 0x00000000
\r
67 #define SVNSLC_SHOWEXTERNAL 0x00000000
\r
68 #define SVNSLC_SHOWINCOMPLETE 0x00000000
\r
69 #define SVNSLC_SHOWINEXTERNALS 0x00000000
\r
70 #define SVNSLC_SHOWREMOVEDANDPRESENT 0x00000000
\r
71 #define SVNSLC_SHOWLOCKS 0x00000000
\r
72 #define SVNSLC_SHOWDIRECTFILES 0x00000000
\r
73 #define SVNSLC_SHOWDIRECTFOLDER 0x00000000
\r
74 #define SVNSLC_SHOWEXTERNALFROMDIFFERENTREPO 0x00000000
\r
75 #define SVNSLC_SHOWSWITCHED 0x00000000
\r
76 #define SVNSLC_SHOWINCHANGELIST 0x00000000
\r
78 #define SVNSLC_SHOWDIRECTS (SVNSLC_SHOWDIRECTFILES | SVNSLC_SHOWDIRECTFOLDER)
\r
81 #define SVNSLC_SHOWVERSIONED (SVNSLC_SHOWNORMAL|SVNSLC_SHOWMODIFIED|\
\r
82 SVNSLC_SHOWADDED|SVNSLC_SHOWREMOVED|SVNSLC_SHOWCONFLICTED|SVNSLC_SHOWMISSING|\
\r
83 SVNSLC_SHOWREPLACED|SVNSLC_SHOWMERGED|SVNSLC_SHOWIGNORED|SVNSLC_SHOWOBSTRUCTED|\
\r
84 SVNSLC_SHOWEXTERNAL|SVNSLC_SHOWINCOMPLETE|SVNSLC_SHOWINEXTERNALS|\
\r
85 SVNSLC_SHOWEXTERNALFROMDIFFERENTREPO)
\r
87 #define SVNSLC_SHOWVERSIONEDBUTNORMAL (SVNSLC_SHOWMODIFIED|SVNSLC_SHOWADDED|\
\r
88 SVNSLC_SHOWREMOVED|SVNSLC_SHOWCONFLICTED|SVNSLC_SHOWMISSING|\
\r
89 SVNSLC_SHOWREPLACED|SVNSLC_SHOWMERGED|SVNSLC_SHOWIGNORED|SVNSLC_SHOWOBSTRUCTED|\
\r
90 SVNSLC_SHOWEXTERNAL|SVNSLC_SHOWINCOMPLETE|SVNSLC_SHOWINEXTERNALS|\
\r
91 SVNSLC_SHOWEXTERNALFROMDIFFERENTREPO)
\r
93 #define SVNSLC_SHOWVERSIONEDBUTNORMALANDEXTERNALSFROMDIFFERENTREPOS (SVNSLC_SHOWMODIFIED|\
\r
94 SVNSLC_SHOWADDED|SVNSLC_SHOWREMOVED|SVNSLC_SHOWCONFLICTED|SVNSLC_SHOWMISSING|\
\r
95 SVNSLC_SHOWREPLACED|SVNSLC_SHOWMERGED|SVNSLC_SHOWIGNORED|SVNSLC_SHOWOBSTRUCTED|\
\r
96 SVNSLC_SHOWINCOMPLETE|SVNSLC_SHOWEXTERNAL|SVNSLC_SHOWINEXTERNALS)
\r
98 #define SVNSLC_SHOWVERSIONEDBUTNORMALANDEXTERNALS (SVNSLC_SHOWMODIFIED|\
\r
99 SVNSLC_SHOWADDED|SVNSLC_SHOWREMOVED|SVNSLC_SHOWCONFLICTED|SVNSLC_SHOWMISSING|\
\r
100 SVNSLC_SHOWREPLACED|SVNSLC_SHOWMERGED|SVNSLC_SHOWIGNORED|SVNSLC_SHOWOBSTRUCTED|\
\r
101 SVNSLC_SHOWINCOMPLETE)
\r
103 #define SVNSLC_SHOWALL (SVNSLC_SHOWVERSIONED|SVNSLC_SHOWUNVERSIONED)
\r
105 #define SVNSLC_POPALL 0xFFFFFFFFFFFFFFFF
\r
106 #define SVNSLC_POPCOMPAREWITHBASE CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDSVNLC_COMPARE)
\r
107 #define SVNSLC_POPCOMPARE CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDSVNLC_COMPAREWC)
\r
108 #define SVNSLC_POPGNUDIFF CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDSVNLC_GNUDIFF1)
\r
109 #define SVNSLC_POPREVERT CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDSVNLC_REVERT)
\r
110 #define SVNSLC_POPUPDATE CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDSVNLC_UPDATE)
\r
111 #define SVNSLC_POPSHOWLOG CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDSVNLC_LOG)
\r
112 #define SVNSLC_POPOPEN CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDSVNLC_OPEN)
\r
113 #define SVNSLC_POPDELETE CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDSVNLC_DELETE)
\r
114 #define SVNSLC_POPADD CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDSVNLC_ADD)
\r
115 #define SVNSLC_POPIGNORE CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDSVNLC_IGNORE)
\r
116 #define SVNSLC_POPCONFLICT CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDSVNLC_EDITCONFLICT)
\r
117 #define SVNSLC_POPRESOLVE CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDSVNLC_RESOLVECONFLICT)
\r
118 #define SVNSLC_POPLOCK CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDSVNLC_LOCK)
\r
119 #define SVNSLC_POPUNLOCK CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDSVNLC_UNLOCK)
\r
120 #define SVNSLC_POPUNLOCKFORCE CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDSVNLC_UNLOCKFORCE)
\r
121 #define SVNSLC_POPEXPLORE CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDSVNLC_EXPLORE)
\r
122 #define SVNSLC_POPCOMMIT CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDSVNLC_COMMIT)
\r
123 #define SVNSLC_POPPROPERTIES CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDSVNLC_PROPERTIES)
\r
124 #define SVNSLC_POPREPAIRMOVE CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDSVNLC_REPAIRMOVE)
\r
125 #define SVNSLC_POPCHANGELISTS CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDSVNLC_CHECKGROUP)
\r
126 #define SVNSLC_POPBLAME CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDSVNLC_BLAME)
\r
128 #define SVNSLC_IGNORECHANGELIST _T("ignore-on-commit")
\r
130 // This gives up to 64 standard properties and menu entries
\r
131 // plus 192 user-defined properties (should be plenty).
\r
132 // User-defined properties will start at column SVNSLC_NUMCOLUMNS+1
\r
133 // but in the registry, we will record them starting at SVNSLC_USERPROPCOLOFFSET.
\r
135 #define SVNSLC_USERPROPCOLOFFSET 0x40
\r
136 #define SVNSLC_USERPROPCOLLIMIT 0xff
\r
137 #define SVNSLC_MAXCOLUMNCOUNT 0xff
\r
139 // Supporting extreamly long user props makes no sense here --
\r
140 // especially for binary properties. CString uses a pool allocator
\r
141 // that works for up to 256 chars. Make sure we are well below that.
\r
143 #define SVNSLC_MAXUSERPROPLENGTH 0x70
\r
145 typedef int (__cdecl *GENERICCOMPAREFN)(const void * elem1, const void * elem2);
\r
146 typedef CComCritSecLock<CComCriticalSection> Locker;
\r
148 class CGitStatusListCtrlDropTarget;
\r
151 * A List control, based on the MFC CListCtrl which shows a list of
\r
152 * files with their Subversion status. The control also provides a context
\r
153 * menu to do some Subversion tasks on the selected files.
\r
155 * This is the main control used in many dialogs to show a list of files to
\r
158 class CGitStatusListCtrl :
\r
164 IDSVNLC_REVERT = 1,
\r
172 IDSVNLC_EDITCONFLICT ,
\r
173 IDSVNLC_IGNOREMASK ,
\r
175 IDSVNLC_RESOLVECONFLICT ,
\r
177 IDSVNLC_LOCKFORCE ,
\r
179 IDSVNLC_UNLOCKFORCE ,
\r
182 IDSVNLC_RESOLVETHEIRS ,
\r
183 IDSVNLC_RESOLVEMINE ,
\r
186 IDSVNLC_PROPERTIES ,
\r
189 IDSVNLC_REPAIRMOVE ,
\r
190 IDSVNLC_REMOVEFROMCS ,
\r
192 IDSVNLC_CREATEIGNORECS ,
\r
193 IDSVNLC_CHECKGROUP ,
\r
194 IDSVNLC_UNCHECKGROUP ,
\r
195 IDSVNLC_ADD_RECURSIVE ,
\r
196 IDSVNLC_COMPAREWC ,
\r
199 IDSVNLC_REVERTTOREV ,
\r
201 IDSVNLC_FINDENTRY ,
\r
202 // the IDSVNLC_MOVETOCS *must* be the last index, because it contains a dynamic submenu where
\r
203 // the submenu items get command ID's sequent to this number
\r
206 int GetColumnIndex(int colmask);
\r
207 static inline unsigned __int64 GetContextMenuBit(int i){ return ((unsigned __int64 )0x1)<<i ;}
\r
209 * Sent to the parent window (using ::SendMessage) after a context menu
\r
210 * command has finished if the item count has changed.
\r
212 static const UINT SVNSLNM_ITEMCOUNTCHANGED;
\r
214 * Sent to the parent window (using ::SendMessage) when the control needs
\r
215 * to be refreshed. Since this is done usually in the parent window using
\r
216 * a thread, this message is used to tell the parent to do exactly that.
\r
218 static const UINT SVNSLNM_NEEDSREFRESH;
\r
221 * Sent to the parent window (using ::SendMessage) when the user drops
\r
222 * files on the control. The LPARAM is a pointer to a TCHAR string
\r
223 * containing the dropped path.
\r
225 static const UINT SVNSLNM_ADDFILE;
\r
228 * Sent to the parent window (using ::SendMessage) when the user checks/unchecks
\r
229 * one or more items in the control. The WPARAM contains the number of
\r
230 * checked items in the control.
\r
232 static const UINT SVNSLNM_CHECKCHANGED;
\r
234 CGitStatusListCtrl(void);
\r
235 ~CGitStatusListCtrl(void);
\r
238 * \ingroup TortoiseProc
\r
239 * Helper class for CGitStatusListCtrl which represents
\r
240 * the data for each file shown.
\r
246 FileEntry() : status(git_wc_status_unversioned)
\r
247 // , copyfrom_rev(GIT_REV_ZERO)
\r
248 , last_commit_date(0)
\r
249 , last_commit_rev(GIT_REV_ZERO)
\r
250 // , remoterev(GIT_REV_ZERO)
\r
251 , textstatus(git_wc_status_unversioned)
\r
252 , propstatus(git_wc_status_unversioned)
\r
253 // , remotestatus(git_wc_status_unversioned)
\r
254 // , remotetextstatus(git_wc_status_unversioned)
\r
255 // , remotepropstatus(git_wc_status_unversioned)
\r
259 , inunversionedfolder(false)
\r
260 , inexternal(false)
\r
261 , differentrepo(false)
\r
265 , Revision(GIT_REV_ZERO)
\r
266 , isConflicted(false)
\r
267 // , present_props()
\r
269 /// , working_size(SVN_WC_ENTRY_WORKING_SIZE_UNKNOWN)
\r
271 // , depth(git_depth_unknown)
\r
274 const CTGitPath& GetPath() const
\r
278 const bool IsChecked() const
\r
282 CString GetRelativeGitPath() const
\r
284 if (path.IsEquivalentTo(basepath))
\r
285 return path.GetGitPathString();
\r
286 return path.GetGitPathString().Mid(basepath.GetGitPathString().GetLength()+1);
\r
288 // const bool IsLocked() const
\r
290 // return !(lock_token.IsEmpty() && lock_remotetoken.IsEmpty());
\r
292 // const bool HasNeedsLock() const
\r
294 // return needslock;
\r
296 const bool IsFolder() const
\r
300 const bool IsInExternal() const
\r
304 const bool IsNested() const
\r
308 const bool IsFromDifferentRepository() const
\r
310 return differentrepo;
\r
312 CString GetDisplayName() const
\r
314 CString const& chopped = path.GetDisplayString(&basepath);
\r
315 if (!chopped.IsEmpty())
\r
321 // "Display name" must not be empty.
\r
322 return path.GetFileOrDirectoryName();
\r
325 CString GetChangeList() const
\r
329 // CString GetURL() const
\r
334 git_wc_status_kind status; ///< local status
\r
335 git_wc_status_kind textstatus; ///< local text status
\r
336 git_wc_status_kind propstatus; ///< local property status
\r
339 CTGitPath path; ///< full path of the file
\r
340 CTGitPath basepath; ///< common ancestor path of all files
\r
342 CString changelist; ///< the name of the changelist the item belongs to
\r
344 CString last_commit_author; ///< the author which last committed this item
\r
345 CTime last_commit_date; ///< the date when this item was last committed
\r
346 git_revnum_t last_commit_rev; ///< the revision where this item was last committed
\r
348 git_revnum_t remoterev; ///< the revision in HEAD of the repository
\r
349 bool copied; ///< if the file/folder is added-with-history
\r
350 bool switched; ///< if the file/folder is switched to another url
\r
351 bool checked; ///< if the file is checked in the list control
\r
352 bool inunversionedfolder; ///< if the file is inside an unversioned folder
\r
353 bool inexternal; ///< if the item is in an external folder
\r
354 bool differentrepo; ///< if the item is from a different repository than the rest
\r
355 bool direct; ///< directly included (TRUE) or just a child of a folder
\r
356 bool isfolder; ///< TRUE if entry refers to a folder
\r
357 bool isNested; ///< TRUE if the folder from a different repository and/or path
\r
358 bool isConflicted; ///< TRUE if a file entry is conflicted, i.e. if it has the conflicted paths set
\r
359 bool needslock; ///< TRUE if the Git:needs-lock property is set
\r
360 git_revnum_t Revision; ///< the base revision
\r
361 // PropertyList present_props; ///< cacheable properties present in BASE
\r
362 bool keeplocal; ///< Whether a local copy of this entry should be kept in the working copy after a deletion has been committed
\r
363 git_depth_t depth; ///< the depth of this entry
\r
364 friend class CGitStatusListCtrl;
\r
365 friend class CGitStatusListCtrlDropTarget;
\r
366 friend class CSorter;
\r
370 * \ingroup TortoiseProc
\r
371 * Helper class for CGitStatusListCtrl that represents
\r
372 * the columns visible and their order as well as
\r
373 * persisting that data in the registry.
\r
375 * It assigns logical index values to the (potential) columns:
\r
376 * 0 .. GitSLC_NUMCOLUMNS-1 contain the standard attributes
\r
377 * GitSLC_USERPROPCOLOFFSET .. GitSLC_MAXCOLUMNCOUNT are user props.
\r
379 * The column vector contains the columns that are actually
\r
380 * available in the control.
\r
382 * Since the set of userprops may change from one WC to another,
\r
383 * we also store the settings (width and order) for those
\r
384 * userprops that are not used in this WC.
\r
386 * A userprop is considered "in use", if the respective column
\r
387 * is not hidden or if at least one item has this property set.
\r
389 class ColumnManager
\r
393 /// construction / destruction
\r
395 ColumnManager (CListCtrl* control) : control (control) {};
\r
396 ~ColumnManager() {};
\r
398 /// registry access
\r
400 void ReadSettings (DWORD defaultColumns, const CString& containerName);
\r
401 void WriteSettings() const;
\r
403 /// read column definitions
\r
405 int GetColumnCount() const; ///< total number of columns
\r
406 bool IsVisible (int column) const;
\r
407 int GetInvisibleCount() const;
\r
408 bool IsRelevant (int column) const;
\r
409 bool IsUserProp (int column) const;
\r
410 CString GetName (int column) const;
\r
411 int GetWidth (int column, bool useDefaults = false) const;
\r
412 int GetVisibleWidth (int column, bool useDefaults) const;
\r
414 /// switch columns on and off
\r
416 void SetVisible (int column, bool visible);
\r
418 /// tracking column modifications
\r
420 void ColumnMoved (int column, int position);
\r
421 void ColumnResized (int column);
\r
423 /// call these to update the user-prop list
\r
424 /// (will also auto-insert /-remove new list columns)
\r
426 //void UpdateUserPropList (const std::vector<FileEntry*>& files);
\r
427 //void UpdateRelevance ( const std::vector<FileEntry*>& files
\r
428 // , const std::vector<size_t>& visibleFiles);
\r
430 /// don't clutter the context menu with irrelevant prop info
\r
432 bool AnyUnusedProperties() const;
\r
433 void RemoveUnusedProps();
\r
435 /// bring everything back to its "natural" order
\r
437 void ResetColumns (DWORD defaultColumns);
\r
441 /// initialization utilities
\r
443 void ParseUserPropSettings ( const CString& userPropList
\r
444 , const CString& shownUserProps);
\r
445 void ParseWidths (const CString& widths);
\r
446 void SetStandardColumnVisibility (DWORD visibility);
\r
447 void ParseColumnOrder (const CString& widths);
\r
449 /// map internal column order onto visible column order
\r
450 /// (all invisibles in front)
\r
452 std::vector<int> GetGridColumnOrder();
\r
453 void ApplyColumnOrder();
\r
455 /// utilities used when writing data to the registry
\r
457 DWORD GetSelectedStandardColumns() const;
\r
458 CString GetUserPropList() const;
\r
459 CString GetShownUserProps() const;
\r
460 CString GetWidthString() const;
\r
461 CString GetColumnOrderString() const;
\r
463 /// our parent control and its data
\r
465 CListCtrl* control;
\r
467 /// where to store in the registry
\r
469 CString registryPrefix;
\r
471 /// all columns in their "natural" order
\r
475 int index; ///< is a user prop when < GitSLC_USERPROPCOLOFFSET
\r
478 bool relevant; ///< set to @a visible, if no *shown* item has that property
\r
481 std::vector<ColumnInfo> columns;
\r
483 /// user-defined properties
\r
487 CString name; ///< is a user prop when < GitSLC_USERPROPCOLOFFSET
\r
491 std::vector<UserProp> userProps;
\r
493 /// stored result from last UpdateUserPropList() call
\r
495 std::set<CString> itemProps;
\r
497 /// global column ordering including unused user props
\r
499 std::vector<int> columnOrder;
\r
502 * \ingroup TortoiseProc
\r
503 * Simple utility class that defines the sort column order.
\r
509 CSorter ( ColumnManager* columnManager
\r
513 bool operator() ( const CTGitPath* entry1
\r
514 , const CTGitPath* entry2) const;
\r
518 ColumnManager* columnManager;
\r
524 * Initializes the control, sets up the columns.
\r
525 * \param dwColumns mask of columns to show. Use the GitSLC_COLxxx defines.
\r
526 * \param sColumnInfoContainer Name of a registry key
\r
527 * where the position and visibility of each column
\r
528 * is saved and used from. If the registry key
\r
529 * doesn't exist, the default order is used
\r
530 * and dwColumns tells which columns are visible.
\r
531 * \param dwContextMenus mask of context menus to be active, not all make sense for every use of this control.
\r
532 * Use the GitSLC_POPxxx defines.
\r
533 * \param bHasCheckboxes TRUE if the control should show check boxes on the left of each file entry.
\r
535 void Init(DWORD dwColumns, const CString& sColumnInfoContainer, unsigned __int64 dwContextMenus = (SVNSLC_POPALL ^ SVNSLC_POPCOMMIT), bool bHasCheckboxes = true);
\r
537 * Sets a background image for the list control.
\r
538 * The image is shown in the right bottom corner.
\r
539 * \param nID the resource ID of the bitmap to use as the background
\r
541 bool SetBackgroundImage(UINT nID);
\r
543 * Makes the 'ignore' context menu only ignore the files and not add the
\r
544 * folder which gets the Git:ignore property changed to the list.
\r
545 * This is needed e.g. for the Add-dialog, where the modified folder
\r
546 * showing up would break the resulting "add" command.
\r
548 void SetIgnoreRemoveOnly(bool bRemoveOnly = true) {m_bIgnoreRemoveOnly = bRemoveOnly;}
\r
550 * The unversioned items are by default shown after all other files in the list.
\r
551 * If that behavior should be changed, set this value to false.
\r
553 void PutUnversionedLast(bool bLast) {m_bUnversionedLast = bLast;}
\r
555 * Fetches the Subversion status of all files and stores the information
\r
556 * about them in an internal array.
\r
557 * \param sFilePath path to a file which contains a list of files and/or folders for which to
\r
558 * fetch the status, separated by newlines.
\r
559 * \param bUpdate TRUE if the remote status is requested too.
\r
560 * \return TRUE on success.
\r
562 BOOL GetStatus ( const CTGitPathList* pathList=NULL
\r
563 , bool bUpdate = false
\r
564 , bool bShowIgnores = false
\r
565 , bool bShowUnRev=false
\r
566 , bool bShowUserProps = false);
\r
569 * Populates the list control with the previously (with GetStatus) gathered status information.
\r
570 * \param dwShow mask of file types to show. Use the GitSLC_SHOWxxx defines.
\r
571 * \param dwCheck mask of file types to check. Use GitLC_SHOWxxx defines. Default (0) means 'use the entry's stored check status'
\r
573 void Show(DWORD dwShow, DWORD dwCheck = 0, bool bShowFolders = true,BOOL updateStatusList=FALSE);
\r
574 void Show(DWORD dwShow, const CTGitPathList& checkedList, bool bShowFolders = true);
\r
577 * Copies the selected entries in the control to the clipboard. The entries
\r
578 * are separated by newlines.
\r
579 * \param dwCols the columns to copy. Each column is separated by a tab.
\r
581 bool CopySelectedEntriesToClipboard(DWORD dwCols);
\r
584 * If during the call to GetStatus() some Git:externals are found from different
\r
585 * repositories than the first one checked, then this method returns TRUE.
\r
587 BOOL HasExternalsFromDifferentRepos() const {return m_bHasExternalsFromDifferentRepos;}
\r
590 * If during the call to GetStatus() some Git:externals are found then this method returns TRUE.
\r
592 BOOL HasExternals() const {return m_bHasExternals;}
\r
595 * If unversioned files are found (but not necessarily shown) TRUE is returned.
\r
597 BOOL HasUnversionedItems() {return m_bHasUnversionedItems;}
\r
600 * If there are any locks in the working copy, TRUE is returned
\r
602 BOOL HasLocks() const {return m_bHasLocks;}
\r
605 * If there are any change lists defined in the working copy, TRUE is returned
\r
607 BOOL HasChangeLists() const {return m_bHasChangeLists;}
\r
610 * Returns the file entry data for the list control index.
\r
612 //CGitStatusListCtrl::FileEntry * GetListEntry(UINT_PTR index);
\r
615 * Returns the file entry data for the specified path.
\r
616 * \note The entry might not be shown in the list control.
\r
618 //CGitStatusListCtrl::FileEntry * GetListEntry(const CTGitPath& path);
\r
621 * Returns the index of the list control entry with the specified path,
\r
622 * or -1 if the path is not in the list control.
\r
624 int GetIndex(const CTGitPath& path);
\r
627 * Returns the file entry data for the specified path in the list control.
\r
629 //CGitStatusListCtrl::FileEntry * GetVisibleListEntry(const CTGitPath& path);
\r
632 * Returns a String containing some statistics like number of modified, normal, deleted,...
\r
635 CString GetStatisticsString();
\r
638 * Set a static control which will be updated automatically with
\r
639 * the number of selected and total files shown in the list control.
\r
641 void SetStatLabel(CWnd * pStatLabel){m_pStatLabel = pStatLabel;};
\r
644 * Set a tri-state checkbox which is updated automatically if the
\r
645 * user checks/unchecks file entries in the list control to indicate
\r
646 * if all files are checked, none are checked or some are checked.
\r
648 void SetSelectButton(CButton * pButton) {m_pSelectButton = pButton;}
\r
651 * Set a button which is de-/activated automatically. The button is
\r
652 * only set active if at least one item is selected.
\r
654 void SetConfirmButton(CButton * pButton) {m_pConfirmButton = pButton;}
\r
657 * Select/unselect all entries in the list control.
\r
658 * \param bSelect TRUE to check, FALSE to uncheck.
\r
660 void SelectAll(bool bSelect, bool bIncludeNoCommits = false);
\r
662 /** Set a checkbox on an entry in the listbox
\r
663 * Keeps the listctrl checked state and the FileEntry's checked flag in sync
\r
665 void SetEntryCheck(CTGitPath* pEntry, int listboxIndex, bool bCheck);
\r
667 /** Write a list of the checked items' paths into a path list
\r
669 void WriteCheckedNamesToPathList(CTGitPathList& pathList);
\r
671 /** fills in \a lMin and \a lMax with the lowest/highest revision of all
\r
672 * files/folders in the working copy.
\r
673 * \param bShownOnly if true, the min/max revisions are calculated only for shown items
\r
674 * \param bCheckedOnly if true, the min/max revisions are calculated only for items
\r
675 * which are checked.
\r
676 * \remark Since an item can only be checked if it is visible/shown in the list control
\r
677 * bShownOnly is automatically set to true if bCheckedOnly is true
\r
679 void GetMinMaxRevisions(git_revnum_t& rMin, git_revnum_t& rMax, bool bShownOnly, bool bCheckedOnly);
\r
682 * Returns the parent directory of all entries in the control.
\r
683 * if \a bStrict is set to false, then the paths passed to the control
\r
684 * to fetch the status (in GetStatus()) are used if possible.
\r
686 CString GetCommonDirectory(bool bStrict);
\r
689 * Returns the parent url of all entries in the control.
\r
690 * if \a bStrict is set to false, then the paths passed to the control
\r
691 * to fetch the status (in GetStatus()) are used if possible.
\r
693 CTGitPath GetCommonURL(bool bStrict);
\r
696 * Sets a pointer to a boolean variable which is checked periodically
\r
697 * during the status fetching. As soon as the variable changes to true,
\r
698 * the operations stops.
\r
700 void SetCancelBool(bool * pbCanceled) {m_pbCanceled = pbCanceled;}
\r
703 * Sets the string shown in the control while the status is fetched.
\r
704 * If not set, it defaults to "please wait..."
\r
706 void SetBusyString(const CString& str) {m_sBusy = str;}
\r
707 void SetBusyString(UINT id) {m_sBusy.LoadString(id);}
\r
710 * Sets the string shown in the control if no items are shown. This
\r
711 * can happen for example if there's nothing modified and the unversioned
\r
712 * files aren't shown either, so there's nothing to commit.
\r
713 * If not set, it defaults to "file list is empty".
\r
715 void SetEmptyString(const CString& str) {m_sEmpty = str;}
\r
716 void SetEmptyString(UINT id) {m_sEmpty.LoadString(id);}
\r
719 * Determines if the control should recurse into unversioned folders
\r
720 * when fetching the status. The default behavior is defined by the
\r
721 * registry key HKCU\Software\TortoiseGit\UnversionedRecurse, which
\r
722 * is read in the Init() method.
\r
723 * If you want to change the behavior, call this method *after*
\r
726 void SetUnversionedRecurse(bool bUnversionedRecurse) {m_bUnversionedRecurse = bUnversionedRecurse;}
\r
729 * Returns the number of selected items
\r
731 LONG GetSelected(){return m_nSelected;};
\r
734 * Enables dropping of files on the control.
\r
736 bool EnableFileDrop();
\r
739 * Checks if the path already exists in the list.
\r
741 bool HasPath(const CTGitPath& path);
\r
743 * Checks if the path is shown/visible in the list control.
\r
745 bool IsPathShown(const CTGitPath& path);
\r
747 * Forces the children to be checked when the parent folder is checked,
\r
748 * and the parent folder to be unchecked if one of its children is unchecked.
\r
750 void CheckChildrenWithParent(bool bCheck) {m_bCheckChildrenWithParent = bCheck;}
\r
753 * Allows checking the items if change lists are present. If set to false,
\r
754 * items are not checked if at least one changelist is available.
\r
756 void CheckIfChangelistsArePresent(bool bCheck) {m_bCheckIfGroupsExist = bCheck;}
\r
758 * Returns the currently used show flags passed to the Show() method.
\r
760 DWORD GetShowFlags() {return m_dwShow;}
\r
762 CString GetLastErrorMessage() {return m_sLastError;}
\r
764 void Block(BOOL block, BOOL blockUI) {m_bBlock = block; m_bBlockUI = blockUI;}
\r
766 LONG m_nTargetCount; ///< number of targets in the file passed to GetStatus()
\r
768 CString m_sURL; ///< the URL of the target or "(multiple targets)"
\r
770 GitRev m_HeadRev; ///< the HEAD revision of the repository if bUpdate was TRUE
\r
772 CString m_sUUID; ///< the UUID of the associated repository
\r
774 DECLARE_MESSAGE_MAP()
\r
777 void SaveColumnWidths(bool bSaveToRegistry = false);
\r
778 void Sort(); ///< Sorts the control by columns
\r
779 //void AddEntry(FileEntry * entry, WORD langID, int listIndex); ///< add an entry to the control
\r
780 void RemoveListEntry(int index); ///< removes an entry from the listcontrol and both arrays
\r
781 bool BuildStatistics(); ///< build the statistics and correct the case of files/folders
\r
782 void StartDiff(int fileindex); ///< start the external diff program
\r
783 void StartDiffWC(int fileindex); ///< start the external diff program
\r
785 /// fetch all user properties for all items
\r
786 void FetchUserProperties();
\r
788 /// Process one line of the command file supplied to GetStatus
\r
789 bool FetchStatusForSingleTarget(GitConfig& config, GitStatus& status, const CTGitPath& target,
\r
790 bool bFetchStatusFromRepository, CStringA& strCurrentRepositoryUUID, CTGitPathList& arExtPaths,
\r
791 bool bAllDirect, git_depth_t depth = git_depth_infinity, bool bShowIgnores = false);
\r
793 /// Create 'status' data for each item in an unversioned folder
\r
794 void AddUnversionedFolder(const CTGitPath& strFolderName, const CTGitPath& strBasePath, GitConfig * config);
\r
796 /// Read the all the other status items which result from a single GetFirstStatus call
\r
797 void ReadRemainingItemsStatus(GitStatus& status, const CTGitPath& strBasePath, CStringA& strCurrentRepositoryUUID, CTGitPathList& arExtPaths, GitConfig * config, bool bAllDirect);
\r
799 /// Clear the status vector (contains custodial pointers)
\r
800 void ClearStatusArray();
\r
802 /// Sort predicate function - Compare the paths of two entries without regard to case
\r
803 //static bool EntryPathCompareNoCase(const FileEntry* pEntry1, const FileEntry* pEntry2);
\r
805 /// Predicate used to build a list of only the versioned entries of the FileEntry array
\r
806 //static bool IsEntryVersioned(const FileEntry* pEntry1);
\r
808 /// Look up the relevant show flags for a particular Git status value
\r
809 DWORD GetShowFlagsFromGitStatus(git_wc_status_kind status);
\r
811 /// Build a FileEntry item and add it to the FileEntry array
\r
812 //const FileEntry* AddNewFileEntry(
\r
813 // const git_wc_status2_t* pGitStatus, // The return from the Git GetStatus functions
\r
814 // const CTGitPath& path, // The path of the item we're adding
\r
815 // const CTGitPath& basePath, // The base directory for this status build
\r
816 // bool bDirectItem, // Was this item the first found by GetFirstFileStatus or by a subsequent GetNextFileStatus call
\r
817 // bool bInExternal, // Are we in an 'external' folder
\r
818 // bool bEntryfromDifferentRepo // if the entry is from a different repository
\r
821 /// Adjust the checkbox-state on all descendants of a specific item
\r
822 //void SetCheckOnAllDescendentsOf(const FileEntry* parentEntry, bool bCheck);
\r
824 /// Build a path list of all the selected items in the list (NOTE - SELECTED, not CHECKED)
\r
825 void FillListOfSelectedItemPaths(CTGitPathList& pathList, bool bNoIgnored = false);
\r
827 /// Enables/Disables group view and adds all groups to the list control.
\r
828 /// If bForce is true, then group view is enabled and the 'null' group is added.
\r
829 bool PrepareGroups(bool bForce = false);
\r
830 /// Returns the group number to which the group header belongs
\r
831 /// If the point is not over a group header, -1 is returned
\r
832 int GetGroupFromPoint(POINT * ppt);
\r
833 /// Returns the number of change lists the selection has
\r
834 size_t GetNumberOfChangelistsInSelection();
\r
836 /// Puts the item to the corresponding group
\r
837 bool SetItemGroup(int item, int groupindex);
\r
839 void CheckEntry(int index, int nListItems);
\r
840 void UncheckEntry(int index, int nListItems);
\r
842 /// sends an GitSLNM_CHECKCHANGED notification to the parent
\r
843 void NotifyCheck();
\r
845 int CellRectFromPoint(CPoint& point, RECT *cellrect, int *col) const;
\r
847 void OnContextMenuList(CWnd * pWnd, CPoint point);
\r
848 void OnContextMenuGroup(CWnd * pWnd, CPoint point);
\r
849 void OnContextMenuHeader(CWnd * pWnd, CPoint point);
\r
851 virtual void PreSubclassWindow();
\r
852 virtual BOOL PreTranslateMessage(MSG* pMsg);
\r
853 virtual INT_PTR OnToolHitTest(CPoint point, TOOLINFO* pTI) const;
\r
854 afx_msg void OnBeginDrag(NMHDR* pNMHDR, LRESULT* pResult);
\r
855 afx_msg BOOL OnToolTipText(UINT id, NMHDR *pNMHDR, LRESULT *pResult);
\r
856 afx_msg void OnHdnItemclick(NMHDR *pNMHDR, LRESULT *pResult);
\r
857 afx_msg void OnLvnItemchanging(NMHDR *pNMHDR, LRESULT *pResult);
\r
858 afx_msg BOOL OnLvnItemchanged(NMHDR *pNMHDR, LRESULT *pResult);
\r
859 afx_msg void OnColumnResized(NMHDR *pNMHDR, LRESULT *pResult);
\r
860 afx_msg void OnColumnMoved(NMHDR *pNMHDR, LRESULT *pResult);
\r
861 afx_msg void OnContextMenu(CWnd* pWnd, CPoint point);
\r
863 void CreateChangeList(const CString& name);
\r
865 afx_msg void OnNMDblclk(NMHDR *pNMHDR, LRESULT *pResult);
\r
866 afx_msg void OnLvnGetInfoTip(NMHDR *pNMHDR, LRESULT *pResult);
\r
867 afx_msg void OnNMCustomdraw(NMHDR *pNMHDR, LRESULT *pResult);
\r
868 afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message);
\r
869 afx_msg UINT OnGetDlgCode();
\r
870 afx_msg void OnNMReturn(NMHDR *pNMHDR, LRESULT *pResult);
\r
871 afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
\r
872 afx_msg void OnPaint();
\r
873 afx_msg void OnHdnBegintrack(NMHDR *pNMHDR, LRESULT *pResult);
\r
874 afx_msg void OnHdnItemchanging(NMHDR *pNMHDR, LRESULT *pResult);
\r
875 afx_msg void OnDestroy();
\r
878 void FileSaveAs(CTGitPath *path);
\r
879 int RevertSelectedItemToVersion();
\r
882 bool * m_pbCanceled;
\r
883 bool m_bAscending; ///< sort direction
\r
884 int m_nSortedColumn; ///< which column to sort
\r
885 bool m_bHasCheckboxes;
\r
886 bool m_bUnversionedLast;
\r
887 bool m_bHasExternalsFromDifferentRepos;
\r
888 bool m_bHasExternals;
\r
889 BOOL m_bHasUnversionedItems;
\r
891 bool m_bHasChangeLists;
\r
892 //typedef std::vector<FileEntry*> FileEntryVector;
\r
893 //FileEntryVector m_arStatusArray;
\r
894 std::vector<CTGitPath*> m_arStatusArray;
\r
895 std::vector<size_t> m_arListArray;
\r
896 std::map<CString, int> m_changelists;
\r
897 bool m_bHasIgnoreGroup;
\r
898 //CTGitPathList m_ConflictFileList;
\r
899 CTGitPathList m_StatusFileList;
\r
900 CTGitPathList m_UnRevFileList;
\r
901 CTGitPathList m_IgnoreFileList;
\r
902 //CTGitPathList m_StatusUrlList;
\r
903 CString m_sLastError;
\r
905 LONG m_nUnversioned;
\r
910 LONG m_nConflicted;
\r
914 DWORD m_dwDefaultColumns;
\r
916 bool m_bShowFolders;
\r
917 bool m_bShowIgnores;
\r
919 unsigned __int64 m_dwContextMenus;
\r
924 bool m_bIgnoreRemoveOnly;
\r
925 bool m_bCheckIfGroupsExist;
\r
926 bool m_bFileDropsEnabled;
\r
931 CWnd * m_pStatLabel;
\r
932 CButton * m_pSelectButton;
\r
933 CButton * m_pConfirmButton;
\r
938 CString m_sNoPropValueText;
\r
940 bool m_bUnversionedRecurse;
\r
942 bool m_bCheckChildrenWithParent;
\r
943 CGitStatusListCtrlDropTarget * m_pDropTarget;
\r
945 ColumnManager m_ColumnManager;
\r
947 std::map<CString,bool> m_mapFilenameToChecked; ///< Remember manually de-/selected items
\r
948 CComCriticalSection m_critSec;
\r
950 friend class CGitStatusListCtrlDropTarget;
\r
954 FILELIST_MODIFY= 0x1,
\r
955 FILELIST_UNVER = 0x2,
\r
956 FILELIST_IGNORE =0x4
\r
959 int UpdateFileList(git_revnum_t hash,CTGitPathList *List=NULL);
\r
960 int UpdateFileList(int mask, bool once=true,CTGitPathList *List=NULL);
\r
961 int UpdateUnRevFileList(CTGitPathList *List=NULL);
\r
962 int UpdateIgnoreFileList(CTGitPathList *List=NULL);
\r
964 int UpdateWithGitPathList(CTGitPathList &list);
\r
966 void AddEntry(CTGitPath* path, WORD langID, int ListIndex);
\r
969 git_revnum_t m_CurrentVersion;
\r
975 class CGitStatusListCtrlDropTarget : public CIDropTarget
\r
978 CGitStatusListCtrlDropTarget(CGitStatusListCtrl * pGitStatusListCtrl):CIDropTarget(pGitStatusListCtrl->m_hWnd){m_pGitStatusListCtrl = pGitStatusListCtrl;}
\r
980 virtual bool OnDrop(FORMATETC* pFmtEtc, STGMEDIUM& medium, DWORD * /*pdwEffect*/, POINTL pt);
\r
981 virtual HRESULT STDMETHODCALLTYPE DragOver(DWORD grfKeyState, POINTL pt, DWORD __RPC_FAR *pdwEffect);
\r
983 CGitStatusListCtrl * m_pGitStatusListCtrl;
\r